1 /* 2 * gcc -std=c99 -o tcpCli ./tcpCli.c -lpthread 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 <stdlib.h> 12 #include <errno.h> 13 #include <pthread.h> 14 15 const int PORT = 7766; 16 17 void* func(void *arg) 18 { 19 int fd = socket(AF_INET, SOCK_STREAM, 0); 20 if (fd == -1) 21 { 22 perror("socket"); 23 return (void*)0; 24 } 25 26 struct sockaddr_in addr; 27 memset(&addr, 0, sizeof(addr)); 28 addr.sin_family = AF_INET; 29 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 30 addr.sin_port = htons(PORT); 31 32 // get send buffer size 33 int iWBufSize; 34 socklen_t optLen = sizeof(iWBufSize); 35 getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &iWBufSize, &optLen); 36 printf("Write buffer size = %d\n", iWBufSize); 37 38 int iRBufSize; 39 optLen = sizeof(iRBufSize); 40 getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &iRBufSize, &optLen); 41 printf("Read buffer size = %d\n", iRBufSize); 42 43 if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) 44 { 45 perror("connect"); 46 return (void*)0; 47 } 48 49 char buf[1500] = "hello world!"; 50 int iCount = 0; 51 while (1) 52 { 53 sprintf(buf, "%d", iCount); 54 int iRet = send(fd, buf, strlen(buf), 0); 55 if (iRet == -1) 56 { 57 perror("sendto"); 58 break; 59 } 60 else 61 { 62 // printf("Send data len [%d]\n", iRet); 63 iCount++; 64 } 65 if (iCount % 100 == 0) 66 { 67 // printf("Send package count %d\n", iCount); 68 sleep(5); 69 } 70 } 71 printf("Send package count %d\n", iCount); 72 close(fd); 73 74 return (void*)0; 75 } 76 int main(int argc, char **argv) 77 { 78 if (argc != 2) 79 { 80 printf("Usage:%s thread_num\n", argv[0]); 81 return 0; 82 } 83 84 int iThreadNum = atoi(argv[1]); 85 printf("ThreadNum [%d]\n", iThreadNum); 86 pthread_t *pTid = (pthread_t*)malloc(sizeof(pthread_t) * iThreadNum); 87 for (int i = 0; i < iThreadNum; ++i) 88 { 89 pthread_create(&pTid[i], NULL, func, NULL); 90 } 91 92 for (int i = 0; i < iThreadNum; ++i) 93 { 94 pthread_join(pTid[i], NULL); 95 } 96 97 return 0; 98 }
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 #include <pthread.h> 13 14 const int PORT = 7766; 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 printf("Port %d\n", PORT); 26 struct sockaddr_in addr; 27 memset(&addr, 0, sizeof(addr)); 28 addr.sin_family = AF_INET; 29 addr.sin_addr.s_addr = INADDR_ANY; 30 addr.sin_port = htons(PORT); 31 32 if (-1 == bind(fd, (struct sockaddr*)&addr, sizeof(addr))) 33 { 34 perror("bind"); 35 return errno; 36 } 37 38 if (-1 == listen(fd, 5)) 39 { 40 perror("listen"); 41 return errno; 42 } 43 44 struct sockaddr_in cli_addr; 45 socklen_t cli_addr_len = sizeof(cli_addr); 46 sleep(1000000); 47 48 int client = accept(fd, (struct sockaddr*)&cli_addr, &cli_addr_len); 49 if (client < 0) 50 { 51 perror("accept"); 52 return errno; 53 } 54 55 char buf[1500]; 56 int iCount = 0; 57 int iZero = 0; 58 while(1) 59 { 60 memset(buf, 0, 1024); 61 int iRet = recv(client, buf, 1500, 0); 62 printf("Recv package count[%d]\t", iCount); 63 printf("recv content [%s]\n", buf); 64 iRet = send(client, buf, iRet, 0); 65 66 iRet = iRet/iZero; 67 } 68 close(fd); 69 70 return 0; 71 }
实验结果:
执行:tcpCli 15 的结果
这是使用grep过滤了tcpSvr的显示结果:
这是使用grep过滤了tcpCli的显示结果:
这是过了一段时间后,tcpCli输出的结果:
TCP状态转移图:
然后根据这些结果以及TCP状态转移图,可以得出如下结论:
这段解释的意思就是,当服务端未处理连接队列满的时候,它就会丢掉client端发送的三次握手中的最后一个ACK包,这就会导致,client端以为自己已经建立连接了,但是实际在server端没有连接,同时也解释了tcpdump抓包看到的,为什么server一直不停的发送三次握手的第二次数据包(SYN+ACK)。
另外,关于这种类似的问题,就像知乎浅墨说的,策略在不停的改变,不要听信网上别人的说法,自己动手试一下就可以了。