• 网络编程-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网络编程

     
     
     
     
     
     
     
     
  • 相关阅读:
    mybatis的mapper特殊字符转移以及动态SQL条件查询
    MySQL查询结果集字符串操作之多行合并与单行分割
    MySQL查询之内连接,外连接查询场景的区别与不同
    SpringBoot异步使用@Async原理及线程池配置
    SpringBoot 属性配置文件数据注入配置和yml与properties区别
    MySQL实战45讲第33讲
    Beta冲刺第1次
    Beta冲刺第5次
    Beta冲刺第4次
    Beta冲刺第3次
  • 原文地址:https://www.cnblogs.com/dennis-wong/p/12083966.html
Copyright © 2020-2023  润新知