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]\n", iRet);
50             printf("Send content [%s]\n", 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\n");
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]\n", iRet);
60         printf("recv content [%s]\n", 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\n", iWBufSize);
35 
36     int iRBufSize;
37     optLen = sizeof(iRBufSize);
38     getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &iRBufSize, &optLen);
39     printf("Read buffer size = %d\n", 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]\n", iRet);
55             iCount++;
56         }
57         if (iCount % 100 == 0)
58         {
59             printf("Send package count %d\n", iCount);
60             sleep(1);
61         }
62     }
63     printf("Send package count %d\n", 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]\n", iRet);
46         printf("Recv package count[%d]\t", iCount);
47         printf("recv content [%s]\n", buf);
48     }
49     close(fd);
50 
51     return 0;
52 }

结果:

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

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

posted @ 2017-01-17 14:05  冷冰若水  阅读(4315)  评论(1编辑  收藏  举报