文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

UDP服务器—实现数据通信

2023-08-30 22:47

关注

目录

前言

1.接口介绍

2.编写服务器

3.编写客户端

4.测试

总结


前言

        在这篇文章中为大家介绍如何通过编码实现数据通信,实现思路是根据前面介绍的网络编程函数编写一个服务端和客户端,实现客户端和服务端双方通信

1.接口介绍

创建套接字

 #include           #include  int socket(int domain, int type, int protocol);

domain:网络通信采用AF_INET

type:提供的服务类型,包含TCP流式服务和UDP数据包服务

实现UDP服务器参数设置为SOCK_DGRAM

protocol:采用的协议,一般设置为0,前面的两个参数决定了第三个参数

创建套接字的本质是告诉操作系统要进行网络通信,然后由操作系统在底层维护一个文件缓冲区,创建成功返回该文件描述符,后续数据通信,上层选择将数据放到该文件缓冲区中或者从文件缓冲区中去读数据

返回值:打开的文件描述符

绑定端口号

  #include           #include   int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

sockfd : 创建套接字的返回值

struct sockaddr* addr:使用时填充该结构体的字段

a.协议字段

b.端口号

端口号在进行填充的时候需要先进行转换为网络字节序

#include uint16_t htons(uint16_t hostshort);

获取对方传输过来的端口号时需要将网络字节序转化为本机

#include uint16_t ntohs(uint16_t netshort);

c.IP地址

一般在服务器的实现中IP地址是不需要绑定的

在客户端中发送数据需要填充服务端的IP地址,因为在用户层IP地址是字符串类型,在网络上传输时IP地址是整型数据,所以需要进行转换

#include #include #include in_addr_t inet_addr(const char *cp);

需要获取对方网络中传输过来的IP地址需要将整型转换为字符串类型

#include #include #include char *inet_ntoa(struct in_addr in);

注:因为是网络通信,所以在填充好字段之后需要在传参的时候强转为sockaddr_in

addrlen:结构体的大小

接受数据

#include #include ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,                        struct sockaddr *src_addr, socklen_t *addrlen);

sockfd:文件描述符

buf:用户缓冲区

len:用户缓冲区的大小

flags:设置为0表示阻塞式调用

src_addr:输出型参数,用来获取对方的IP地址和port

addrlen:结构体的大小

发送数据

 #include  #include  ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,                      const struct sockaddr *dest_addr, socklen_t addrlen);

sockfd:文件描述符

buf:用户缓冲区

len:用户缓冲区的大小

flags:设置为0表示阻塞式调用

dest_addr:填充需要发送对端主机的信息,包含IP地址和port端口号

addrlen:结构体的大小

有了上面这些的这些接口,下面我们就可以正式编写一个客户端和一个服务端了

2.编写服务器

形成makefile

.PHONY:allall:udpServer udpClientudpServer:udpServer.ccg++ -o $@ $^ -std=c++11udpClient:udpClient.ccg++ -o $@ $^ -std=c++11.PHONY:cleanclean:rm -rf udpServer udpClient

编写服务器:udpServer.hpp

#pragma once#include #include #include #include #include #include #include #include #include #include #include #include namespace Server{    using namespace std;    const static string defaultIP = "0.0.0.0";    enum {USAGE_ERR = 1, SOCKET_ERR, BIND_ERR};    class udpServer    {    public:        udpServer(uint16_t port, const string &ip = defaultIP)         :_port(port),_ip(ip),_sockfd(-1)        {}        void initServer()        {            //1.创建socket            _sockfd = socket(AF_INET,SOCK_DGRAM,0);            if(_sockfd == -1)            {                cerr<<"socket error:" << errno << strerror(errno) << endl;                exit(SOCKET_ERR);            }            //2.绑定port和ip            struct sockaddr_in local;            bzero(&local,sizeof(local));            local.sin_family = AF_INET;            local.sin_port = htons(_port);            local.sin_addr.s_addr = htonl(INADDR_ANY);            int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));            if(n == -1)            {                cerr<<"bind error:" << errno << strerror(errno) << endl;                exit(BIND_ERR);            }        }        void startServer()        {            char buffer[1024];            for(;;)            {                struct sockaddr_in peer;                socklen_t len = sizeof(peer);                //peer len:输入,输出型参数:用来保存客户端的ip和port                ssize_t s = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);                //打印发送来的数据                if(s)                {                    buffer[s] = { 0 };                    //inet_ntoa:网络字节序->int  int->点分十进制                    string clientIp = inet_ntoa(peer.sin_addr);                    //ntohl:网络字节序->int                    uint16_t clientPort = ntohs(peer.sin_port);                    string message = buffer;                    cout << clientIp << "[" << clientPort << "]" << message << endl;                }            }        }        ~udpServer()        {}    private:        uint16_t _port;        string _ip;        int _sockfd;    };}

启动服务器:udpServer.cc

#include "udpServer.hpp"#include using namespace Server;static void Usage(string proc){    cout << "\nUsage:\n\t" << proc << " local_port\n\n";}int main(int argc, char *argv[]){    if (argc != 2)    {        Usage(argv[0]);        exit(USAGE_ERR);    }    uint16_t port = atoi(argv[1]);    unique_ptr usvr(new udpServer(port));    usvr->initServer();    usvr->startServer();    return 0;}

3.编写客户端

编写客户端:udpClient.hpp

#pragma once#include #include #include #include #include #include #include #include #include #include #include #include namespace Client{    using namespace std;       class udpClient    {    public:        udpClient(const string& serverIp,const uint16_t serverPort)        :_serverIp(serverIp),_serverPort(serverPort),_sockfd(-1) {}        void initClient()        {            //1.创建socket            _sockfd = socket(AF_INET,SOCK_DGRAM,0);            if(_sockfd == -1)            {                cerr<<"socket error:" << errno << strerror(errno) << endl;                exit(2);            }            //client一定需要bind,服务器只有一个,但是客户端有许多个,所以服务端需要显示的绑定端口号            //客户端一般不需要自己显示的绑定,而是由os自动形成端口号进行绑定        }        void run()        {            struct sockaddr_in server;            memset(&server,0,sizeof(server));            server.sin_family = AF_INET;            server.sin_addr.s_addr = inet_addr(_serverIp.c_str());            server.sin_port = htons(_serverPort);            string message;            while(1)            {                cout << "请输入:";                cin >> message;                //发送数据到客户端                sendto(_sockfd,message.c_str(),message.size(),0,(const struct sockaddr*)&server,                sizeof(server));            }        }    private:        string _serverIp;        int _sockfd;        uint16_t _serverPort;    };}

启动客户端:udpClient.cc

#include"udpClient.hpp"#includeusing namespace Client;static void Usage(string proc){    cout << "\nUsage:\n\t" << proc << " server_ip server_port\n\n";}int main(int argc,char* argv[]){    if(argc != 3)    {        Usage(argv[0]);        exit(1);    }    string serverip = argv[1];    uint16_t serverport = atoi(argv[2]);    unique_ptr uct(new udpClient(serverip,serverport));    uct->initClient();    uct->run();    return 0;}

4.测试

说明:因为本次是在一台主机上,所以为了做测试将IP地址绑定为"127.0.0.1",该IP地址的特点是专门用来在本主机上做测试,称为本地环回,后续在不同主机上通信的时候只需要将IP地址改为对方主机的IP地址即可。

 此时我们就可以看到当客户端向服务器发送数据时,服务器收到了数据,并且将数据回显出来

总结

通过上面的编码,使用UDP协议简单实现了一个服务器,可以用来进行数据通信了,是不是感觉很神奇呀,看到这里你就会发现,原来网络通信也并不复杂,和系统内部进程间通信有异曲同工之妙关于网络通信的更多细节,后面再一一为大家介绍,我们下次再见!

来源地址:https://blog.csdn.net/qq_65307907/article/details/132149986

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-服务器
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯