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,不知道這個值算的對不對。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM