套接字编程(二)UDP服务端与客户端的通信模拟实现

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

一、前言

二、UDP客户端流程信息

1、创建套接字

2、为套接字绑定地址信息不推荐

3、发送数据将数据放入发送缓冲区中

4、接收数据从socket结构体接收缓冲区中取出数据

5、关闭套接字

三、UDP客户端通信简单模拟实现

1、创建套接字

 2、为套接字绑定地址信息

3、发送数据

4、接收数据

 5、功能函数代码

6、主main函数

7、makefile

 四、UDP通信具体操作

1、使用ifconfig了解虚拟机ip  端口推荐选择10000以上

 2、创建俩个会话一个用来运行服务端程序一个用来运行客户端程序

 3、创建服务端

 4、创建客户端

 5、客户端发送问候hello

 6、服务端收到hello  回复hi

 7、客户端收到服务端回复hi


一、前言

上一篇学习UDP服务端搭建的博文也都是近一个周前写的博客了当时对UDP通信展开了初步学习清楚了网络通信的基本原理练习掌握了关于网络通信的部分接口应用实现了关于UDP服务端的搭建

关于服务端大致流程分为

1、创建套接字在内核中创建一个socket结构体

2、为套接字绑定地址信息给创建的套接字内部描述源端IP和端口

3、从socket结构体中的接收缓冲区中取出数据

4、将数据写入socket结构体中的发送缓冲区中

5、关闭套接字

 这一篇博文大概就是完成UDP通信的另一阶段对于客户端通信的创建与模拟实现。

二、UDP客户端流程信息

具体流程如下

1、创建套接字

建立内核与网卡之间的联系在内核中创建一个socket结构体struct socket

2、为套接字绑定地址信息不推荐

一个端口只能被一个网络进程所占用所以如果进行信息绑定那么这一个主机就只能进行这一个进程的通信了如果在绑定信息之后又想访问其他进程信息就会发出端口冲突因此并不主动推荐客户端这边主动绑定地址信息。

3、发送数据将数据放入发送缓冲区中

    客户端与服务器的一个小的区别就是客户端总是先进行发送请求在进行接收回复而服务端肯定是更主动的先进行数据接收如果有主机发出请求那么才会进行请求的回应。

4、接收数据从socket结构体接收缓冲区中取出数据

5、关闭套接字

三、UDP客户端通信简单模拟实现

在UDP服务端通信的搭建过程中发现所有的实现都贯穿着套接字描述符。所以将套接字描述符sockfd作为私有成员

1、创建套接字

接口中使用到的参数地址域信息、套接字类型、协议类型都为默认的IPV4相关的UDP参数AF_INET、SOCK_DGRAM、IPPROTO_UDP


 2、为套接字绑定地址信息

需要提供ip地址参数以及端口号信息套接字描述符作为私有成员

 下方代码对应ipv4结构体进行各项初始化


3、发送数据
 

① ssize_t sendto(int sockfd,  void *buf,  size_t dlen,

                                int flag,  struct sockaddr *peer,  socklen_t alen);

② sockfd socket返回的套接字描述符

③ buf 发送数据的起始地址

④ dlen 发送数据的长度从buf地址开始发送dlen长度的数据

⑤ flag 默认为0阻塞发送发送缓冲区满了就等着 当发送缓冲区有空间了进行发送

⑥ peer 对端地址信息描述了数据要发送给谁

        描述了信息送往哪里    这里存放的是接收方的信息

⑦ alen 对端地址信息长度

⑧ 返回值 成功返回实际发送数据字节长度失败返回-1


4、接收数据

① ssize_t recvfrom(int sockfd,  void *buf,  size_t dlen,
                                  int flag,  struct sockaddr *peer,  socklen_t  *alen);

② sockfd socket创建的套接字描述符

③ 一块地址空间 里面用来存放我接收得到的数据

④ dlen 接收数据的字节长度

⑤ flag 默认为0当socket接收缓冲区为空的时候进行等待有数据了就进行接收

⑥ peer 对端地址信息描述了接收的数据来自哪里。这里存放的是来自发送方的地址信息

⑦ alen  地址信息长度里面即存放了想要接收的数据长度也存放了实际接收的数据长度

⑧ 成功返回实际接收的数据长度失败返回-1
 


 5、功能函数代码

  1 #include<iostream>
  2 #include<string>
  3 #include<unistd.h>
  4 #include<arpa/inet.h> // 字节序转换接口头文件
  5 #include<netinet/in.h>// 地址结构类型以及协议类型头文件
  6 #include<sys/socket.h>// 套接字接口文件
  7 
  8 class UdpSocket
  9 {
 10   private:
 11     int _sockfd;
 12   public:
 13     UdpSocket():_sockfd(-1){}
 14     ~UdpSocket(){Close();}
 15     bool Sockte() // 创建套接字
 16     {
 17       _sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 18       if(_sockfd<0)
 19       {
 20         perror("socket error\n");
 21         return false;
 22       }
 23       return true;
 24     }
 25     bool Bind(const std::string& ip, uint16_t port)
 26     {
 27         struct sockaddr_in addr; // 定义一个ipv4socket结构体
 28         addr.sin_family = AF_INET;// 初始化addr结构体中的sin_family
 29         addr.sin_port = htons(port);
 30         addr.sin_addr.s_addr = inet_addr(ip.c_str());
 31         socklen_t len = sizeof(struct sockaddr_in);
 32         int ret = bind(_sockfd, (struct sockaddr*)&addr, len);
 33         if(ret<0){
 34           perror("bind error\n");
 35           return false;
 36         }                                                                                
 37         return true;
 38     }
 39     bool Recv(std::string *body, std::string *peer_ip, uint16_t *peer_port)
 40     {
 41         struct sockaddr_in peer;
 42         socklen_t len = sizeof(struct sockaddr_in);
 43         char tmp[4096]={0};
 44         ssize_t ret = recvfrom(_sockfd, tmp, 4096, 0, (struct sockaddr*)&peer, &len);
 45         if(ret<0)
 46         {
 47           perror("recv error");
 48           return false;                                                                  
 49         }
 50         *peer_ip = inet_ntoa(peer.sin_addr);
 51         *peer_port = ntohs(peer.sin_port);
 52         body->assign(tmp, ret); // 从tmp中取出ret长度数据放入body中
 53         return true;
 54     }
 55     bool Send(const std::string &body, const std::string &peer_ip, uint16_t peer_port)
 56     {
 57         struct sockaddr_in addr;
 58         addr.sin_family = AF_INET;
 59         addr.sin_port = htons(peer_port);
 60         addr.sin_addr.s_addr = inet_addr(peer_ip.c_str());
 61         socklen_t len = sizeof(struct sockaddr_in);
 62         ssize_t ret = sendto(_sockfd, body.c_str(), body.size(), 0, (struct sockaddr*)&addr, len);
 63         if(ret < 0){
 64           perror("send error");
 65           return false;
 66         }
 67         return true;
 68     }
 69     bool Close()
 70     {
 71         if(_sockfd != -1)
 72         {
 73           close(_sockfd);
 74           _sockfd = -1;
 75         }
 76         return true;
 77     }
 78 };

6、主main函数

   81 int main(int argc, char* argv[])
   82 {
   83     if(argc != 3)
   84     {
   85       std::cout<<"usage: ./client.cpp 192.168.2.2 9000\n";                             
   86       return -1;
   87     }
   88     std::string srv_ip = argv[1];
   89     uint16_t srv_port = std::atoi(argv[2]);
   90     UdpSocket socket;
   91     // 1、创建套接字
   92     assert(socket.Sockte() == true);
   93     // 2、绑定套接字(不推荐)
   94     while(1){
   95     // 3、发送数据
   96         std::string data;
   97         std::cout<<"client say:";
   98         fflush(stdout);
   99         std::cin>>data;
  100         assert(socket.Send(data, srv_ip, srv_port) == true);
  101         
  102     // 4、接收数据
  103         data.clear();
  104         //assert(socket.Recv(&data, &srv_ip, &srv_port) == true);
  105         assert(socket.Recv(&data) == true);
  106     }
  107     socket.Close();
  108     return 0;
  109 }

7、makefile

 四、UDP通信具体操作

1、使用ifconfig了解虚拟机ip  端口推荐选择10000以上

使用ens33所标记的inet

绑定端口时推荐给出10000以上

端口范围uint16_t 0~65535       

0~1023这些端口已经被知名服务器使用了SSH22号端口、HTTP80号端口

 2、创建俩个会话一个用来运行服务端程序一个用来运行客户端程序

 3、创建服务端

 4、创建客户端

 5、客户端发送问候hello

 6、服务端收到hello  回复hi

 7、客户端收到服务端回复hi

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“套接字编程(二)UDP服务端与客户端的通信模拟实现” 的相关文章