• tcp/udp只发不接,会丢包还是send失败?


    这篇文章源于我看libevent的源码时想到的问题,对于libevent的buffer机制,如果接受端一直不取数据的话,会怎样?如果丢包,不现实,因为会导致数据丢失,如果不丢包,就会导致占用内存一直扩大。

    由此我想到对于tcp/udp如果一直发,接收端不调用recv取数据会怎样,是会导致send失败,还是多余的数据丢弃?想再多还不如写个代码试一试,下面看代码。

    tcp:client端一直发,sever端接受连接后不调用recv

    客户端

     1 /*
     2  * gcc -o tcpCli ./tcpCli.c
     3  */
     4 #include <unistd.h>
     5 #include <fcntl.h>
     6 #include <sys/socket.h>
     7 #include <sys/types.h>
     8 #include <netinet/in.h>
     9 #include <arpa/inet.h>
    10 #include <stdio.h>
    11 #include <string.h>
    12 #include <errno.h>
    13 
    14 const int PORT = 8080;
    15 
    16 int main(int argc, char **argv)
    17 {
    18     int fd = socket(AF_INET, SOCK_STREAM, 0);
    19     if (fd == -1)
    20     {
    21         perror("socket");
    22         return errno;
    23     }
    24 
    25     struct sockaddr_in addr;
    26     memset(&addr, 0, sizeof(addr));
    27     addr.sin_family = AF_INET;
    28     addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    29     addr.sin_port = htons(PORT);
    30 
    31     if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
    32     {
    33         perror("connect");
    34         return errno;
    35     }
    36 
    37     fcntl(fd, F_SETFL, O_NONBLOCK);
    38 
    39     char buf[65536] = "hello world!";
    40     while (1)
    41     {
    42         int iRet = send(fd, buf, 65536, 0); 
    43         if (iRet == -1)
    44         {
    45             perror("send");
    46         }
    47         else
    48         {
    49             printf("Send data len [%d]
    ", iRet);
    50             printf("Send content [%s]
    ", buf);
    51         }
    52         sleep(2);
    53     }
    54     close(fd);
    55 
    56     return 0;
    57 }

    服务端

     1 /*
     2  * gcc -o tcpSvr ./tcpSvr.c
     3  */
     4 #include <unistd.h>
     5 #include <sys/socket.h>
     6 #include <sys/types.h>
     7 #include <arpa/inet.h>
     8 #include <netinet/in.h>
     9 #include <stdio.h>
    10 #include <string.h>
    11 #include <errno.h>
    12 
    13 const int PORT = 8080;
    14 
    15 int main(int argc, char **argv)
    16 {
    17     int fd = socket(AF_INET, SOCK_STREAM, 0);
    18     if (fd == -1)
    19     {
    20         perror("socket");
    21         return errno;
    22     }
    23 
    24     struct sockaddr_in addr;
    25     memset(&addr, 0, sizeof(addr));
    26     addr.sin_family = AF_INET;
    27     addr.sin_addr.s_addr = INADDR_ANY;
    28     addr.sin_port = htons(PORT);
    29 
    30     if (-1 == bind(fd, (struct sockaddr*)&addr, sizeof(addr)))
    31     {
    32         perror("bind");
    33         return errno;
    34     }
    35 
    36     if (-1 == listen(fd, 5))
    37     {
    38         perror("listen");
    39         return errno;
    40     }
    41 
    42     struct sockaddr_in cli_addr;
    43     socklen_t len = sizeof(cli_addr);
    44     int client = accept(fd, (struct sockaddr*)&cli_addr, &len);
    45     if (client == -1)
    46     {
    47         perror("accept");
    48         return errno;
    49     }
    50     
    51     printf("accept an client
    ");
    52 
    53     char buf[1024];
    54     while(1)
    55     {
    56         memset(buf, 0, 1024);
    57         //int iRet = recv(client, buf, 10, 0);
    58         int iRet = 0;
    59         printf("recv data len [%d]
    ", iRet);
    60         printf("recv content [%s]
    ", buf);
    61         sleep(2);
    62     }
    63     close(fd);
    64 
    65     return 0;
    66 }

    结果:

    很明显,会导致send发送失败,所以需要注意的是,用send发送数据如果tcp缓冲区空间不足时,只会发送部分数据,这时就需要程序员自己来记录发送位置,等到缓冲区可发送时再继续发送。

    但是获取到的写缓冲区大小和发送的数据大小不一致,不知道是什么原因,这个待后面继续研究。

    udp:client端一直发,一段时间后关闭,sever端等待客户端关闭,再开始接受

    客户端

     1 /*
     2  * gcc -o udpCli ./udpCli.c
     3  */
     4 #include <unistd.h>
     5 #include <sys/socket.h>
     6 #include <sys/types.h>
     7 #include <netinet/in.h>
     8 #include <arpa/inet.h>
     9 #include <stdio.h>
    10 #include <string.h>
    11 #include <errno.h>
    12 
    13 const int PORT = 8080;
    14 
    15 int main(int argc, char **argv)
    16 {
    17     int fd = socket(AF_INET, SOCK_DGRAM, 0);
    18     if (fd == -1)
    19     {
    20         perror("socket");
    21         return errno;
    22     }
    23 
    24     struct sockaddr_in addr;
    25     memset(&addr, 0, sizeof(addr));
    26     addr.sin_family = AF_INET;
    27     addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    28     addr.sin_port = htons(PORT);
    29 
    30     // get send buffer size
    31     int iWBufSize;
    32     socklen_t optLen = sizeof(iWBufSize);
    33     getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &iWBufSize, &optLen);
    34     printf("Write buffer size = %d
    ", iWBufSize);
    35 
    36     int iRBufSize;
    37     optLen = sizeof(iRBufSize);
    38     getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &iRBufSize, &optLen);
    39     printf("Read buffer size = %d
    ", iRBufSize);
    40 
    41     char buf[1500] = "hello world!";
    42     int iCount = 0;
    43     while (1)
    44     {
    45         sprintf(buf, "%d", iCount);
    46         int iRet = sendto(fd, buf, 1500, 0, (struct sockaddr*)&addr, sizeof(addr));
    47         if (iRet == -1)
    48         {
    49             perror("sendto");
    50             break;
    51         }
    52         else
    53         {
    54             // printf("Send data len [%d]
    ", iRet);
    55             iCount++;
    56         }
    57         if (iCount % 100 == 0)
    58         {
    59             printf("Send package count %d
    ", iCount);
    60             sleep(1);
    61         }
    62     }
    63     printf("Send package count %d
    ", iCount);
    64     close(fd);
    65 
    66     return 0;
    67 }

    服务端

     1 /*
     2  * gcc -o udpSvr ./udpSvr.c
     3  */
     4 #include <unistd.h>
     5 #include <sys/socket.h>
     6 #include <sys/types.h>
     7 #include <arpa/inet.h>
     8 #include <netinet/in.h>
     9 #include <stdio.h>
    10 #include <string.h>
    11 #include <errno.h>
    12 
    13 const int PORT = 8080;
    14 
    15 int main(int argc, char **argv)
    16 {
    17     int fd = socket(AF_INET, SOCK_DGRAM, 0);
    18     if (fd == -1)
    19     {
    20         perror("socket");
    21         return errno;
    22     }
    23 
    24     struct sockaddr_in addr;
    25     memset(&addr, 0, sizeof(addr));
    26     addr.sin_family = AF_INET;
    27     addr.sin_addr.s_addr = INADDR_ANY;
    28     addr.sin_port = htons(PORT);
    29 
    30     if (-1 == bind(fd, (struct sockaddr*)&addr, sizeof(addr)))
    31     {
    32         perror("bind");
    33         return errno;
    34     }
    35 
    36     getchar();
    37 
    38     char buf[1500];
    39     int iCount = 0;
    40     while(1)
    41     {
    42         memset(buf, 0, 1024);
    43         int iRet = recv(fd, buf, 1500, 0);
    44         iCount++;
    45         // printf("recv data len [%d]
    ", iRet);
    46         printf("Recv package count[%d]	", iCount);
    47         printf("recv content [%s]
    ", buf);
    48     }
    49     close(fd);
    50 
    51     return 0;
    52 }

    结果:

    可以看到,客户端一共发送1300个包,而服务端仅仅能收到前面69个包,后面的全被丢弃了。

    根据收到的包的个数和每个包的大小,计算出换冲区的大小:103500,不知道这个值算的对不对。

  • 相关阅读:
    【翻译】为了3D游戏粉丝的[(超级)街头霸王4]图形讲座(后篇)
    【翻译】【西川善司】GPU和Shader技术的基础知识 (一共有99回,翻译中)
    Shader Compilation for Multiple Platforms
    【翻译】西川善司为3D游戏粉丝的[索尼克世界大冒险]的图形讲座 3D游戏图形趋势是实时的全局照明
    【翻译】CAPCOM的[MT Framework 2.0]图形讲座
    【翻译】创造让人敬畏的未来SQUARE ENIX的次世代游戏引擎[Luminous Studio]
    业务逻辑层的Helper基类
    漫谈.Net中对象相等
    对微软Web Deploy的一次艰难调试
    在Asp.Net中缓存Ado.Net Entity
  • 原文地址:https://www.cnblogs.com/lit10050528/p/6292828.html
Copyright © 2020-2023  润新知