上述第6种情况【TCP 接收缓冲区 Recv-Q 中的数据未完全被应用程序读取时关闭该 socket】
客户端测试代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
int main(void)
{
int len;
int sockFd;
char sendBuf[256];
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
addr.sin_port = htons(8888);
if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error");
return -1;
}
if (connect(sockFd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("connect error");
close(sockFd);
return -1;
}
memset(sendBuf, 0xFF, sizeof(sendBuf));
send(sockFd, sendBuf, sizeof(sendBuf), 0);
len = recv(sockFd, sendBuf, sizeof(sendBuf), 0);
if (len >= 0)
{
printf("len: %d\n", len);
}
else
{
printf("[line:%d] errno: %d, strerror(errno): %s\n", __LINE__, errno, strerror(errno));
}
close(sockFd);
return 0;
}
服务端测试代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
int main(void)
{
int readLen;
int sockFd;
int clientFd;
char recvBuf[128] = {0};
struct sockaddr_in saddr;
if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error");
return -1;
}
bzero((void*)&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if (bind(sockFd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind error");
close(sockFd);
return -1;
}
if (listen(sockFd, 5) < 0)
{
perror("listen error");
close(sockFd);
return -1;
}
printf("accept waiting, sockFd: %d\n", sockFd);
if ((clientFd = accept(sockFd, NULL, NULL)) == -1)
{
perror("accept error");
close(sockFd);
return -1;
}
while (1)
{
memset(recvBuf, 0, sizeof(recvBuf));
readLen = recv(clientFd, recvBuf, sizeof(recvBuf), 0);
if (readLen > 0)
{
printf("readLen: %d\n", readLen);
}
else if (readLen == 0)
{
printf("client fd is closed!\n");
close(clientFd);
break;
}
else
{
printf("[line:%d] errno: %d, strerror(errno): %s\n", __LINE__, errno, strerror(errno));
close(clientFd);
break;
}
close(clientFd);
break;
}
close(sockFd);
return 0;
}
服务端输出:
![在这里插入图片描述](https://img-blog.csdnimg.cn/36a1c2f8777b45f1a212e479c17f37a6.png)
客户端输出:
![在这里插入图片描述](https://img-blog.csdnimg.cn/384c4f7390614779a0a4e2f0e74a9ed7.png)
wireshark 抓包结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/4aeb4d4015894d078ce118b8e11c86b8.png)
该举例中,客户端发送256字节的数据到服务端,服务端只接收了128字节的数据就关闭了套接字,此时服务端的 TCP 接收缓冲区中还剩128字节未读取,所以服务端发送 RST 到客户端。
上述第5种情况【处理半打开连接】
客户端测试代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
int main(void)
{
int len;
int sockFd;
char sendBuf[256];
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
addr.sin_port = htons(8888);
if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error");
return -1;
}
if (connect(sockFd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("connect error");
close(sockFd);
return -1;
}
memset(sendBuf, 0xFF, sizeof(sendBuf));
send(sockFd, sendBuf, sizeof(sendBuf), 0);
sleep(1);
send(sockFd, sendBuf, sizeof(sendBuf), 0);
close(sockFd);
return 0;
}
服务端测试代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
int main(void)
{
int readLen;
int sockFd;
int clientFd;
char recvBuf[256] = {0};
struct sockaddr_in saddr;
if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error");
return -1;
}
bzero((void*)&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if (bind(sockFd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind error");
close(sockFd);
return -1;
}
if (listen(sockFd, 5) < 0)
{
perror("listen error");
close(sockFd);
return -1;
}
printf("accept waiting, sockFd: %d\n", sockFd);
if ((clientFd = accept(sockFd, NULL, NULL)) == -1)
{
perror("accept error");
close(sockFd);
return -1;
}
while (1)
{
memset(recvBuf, 0, sizeof(recvBuf));
readLen = recv(clientFd, recvBuf, sizeof(recvBuf), 0);
if (readLen > 0)
{
printf("readLen: %d\n", readLen);
}
else if (readLen == 0)
{
printf("client fd is closed!\n");
close(clientFd);
break;
}
else
{
printf("[line:%d] errno: %d, strerror(errno): %s\n", __LINE__, errno, strerror(errno));
close(clientFd);
break;
}
close(clientFd);
break;
}
close(sockFd);
return 0;
}
wireshark 抓包结果: ![在这里插入图片描述](https://img-blog.csdnimg.cn/7bc2b80f782d447cb06ef7fbe7a1c136.png)
该举例中,客户端发送数据到服务端,服务端将数据接收后就关闭了套接字,随后,客户端又发送数据到服务端,因为此时服务端已将套接字关闭,所以服务端会发送 RST 到客户端。