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,不知道这个值算的对不对。