Loading

网络编程-UDP echo server

1. UDP简介 

  UDP 和TCP 的区别包括 1. 面向字节流和面向报文 2. TCP必须要建立连接后才能进行数据交换,但是UDP则并没有连接的建立和释放过程。面向字节流说明,tcp报文段(segment)是没有边界的,当服务器发送多个报文段到客户端时,客户端可能会把着多个报文段合并成一个报文段进行接收。但是对于UDP来说,数据是通过报文段进行传输的。

  如果说TCP协议可以用打电话去比喻,那么UDP协议可以用邮箱来形容。用邮箱传递信息时,虽然有丢失的可能性。但是用户1发送的信件和用户2接受的信件肯定是相同的。

2. 用UDP编写echo server

  使用UDP,我们只需要修改一下socket函数的参数就OK了。

int client_sock = socket(PF_INET, SOCK_DGRAM, 0);

  然后就是创建两个表示客户端和服务端地址的sockaddr_in结构,其中serv_addr的各个字段需要我们自己填充。但是client_addr的各个字段是通过recvfrom通过指针进行自动填充。

struct sockaddr_in serv_addr, client_addr;

  填充serv_addr的各个字段:

 serv_addr.sin_family = AF_INET;
 serv_addr.sin_addr.s_addr = INADDR_ANY;
 serv_addr.sin_port = htons(8080);

   下来使用bind函数将套接字和服务器地址进行绑定。

 if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
     err_exit("bind error");
 }

  数据传输方面使用recv族和sendto进行数据传输,这里值得注意的是只有sendto中的sockaddr_in结构是需要手动填充的,sendto中的地址表示要发送的目标地址。recvfrom中的是获取数据的源地址。下图是echo服务器的交互流程。

      

 

3. 地址长度所遇到的一个坑

   在写echo服务器中遇到一个问题,服务器端在运行过程中总是会出现如下错误:
  在stackoverflow看了下知道了应该是sockaddr的问题。出问题的代码就是下面这一行。问题就在client_addr这块。
int sLen = sendto(serv_sock, buffer, rLen, MSG_CONFIRM,
    (struct sockaddr *)&client_addr, recv_addr_len);

  client_addr是通过服务端调用recvfrom获取的,我心想这也不用我手动填啊,怎么就又错了。又反复看了书上的代码,确定地址的获取方式没有错,通过打印我发现地址确实有问题,端口和地址都不对。在网上搜了下 udp echo server的代码,用可以正常运行的代码和我的代码细细比对,终于发现了问题所在。问题就出在地址长度的初始化上,我一直以为recvfrom中的地址长度是值-返回模式,但是实际上这个值也是要在recvfrom中起作用的。如果这个值不正确,client_addr的值也是错误的,导致服务器无法正常的把数据发送到客户端。就酱。。。

socklen_t recv_addr_len = sizeof(client_addr); //正确的初始化方式
//socklen_t recv_addr_len;                       //错误的初始化方式
int rLen = recvfrom(serv_sock, buffer, MAX_LEN, MSG_WAITALL,
                    (struct sockaddr *)&client_addr, &recv_addr_len);

4. 参考

[3]  TCP/IP网络编程

 
 
 
 
 
 
 
 
posted @ 2019-12-23 15:23  成蹊0xc000  阅读(1509)  评论(0编辑  收藏  举报