這篇文章源於我看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,不知道這個值算的對不對。