如果我们在调用accept函数返回之前, 该客户端TCP发送了一个RST(复位)。在服务器中, 表现为该连接仍在TCP队列中, 等待服务器进程调用accept的时候RST到达。此时返回的套接字是一个已连接,但是却有接受了RST的套接字。
模型图如下:
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <arpa/inet.h> #define SERV_PORT 10001 #define SERV_IP "0.0.0.0" int main(void) { int sfd, cfd; int len, i; //BUFSIZ是系统内嵌的一个宏,用来指定buf大小 char buf[BUFSIZ], clie_IP[BUFSIZ]; struct sockaddr_in serv_addr, clie_addr; socklen_t clie_addr_len; sfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; inet_pton(AF_INET , SERV_IP , &serv_addr.sin_addr.s_addr); serv_addr.sin_port = htons(SERV_PORT); //绑定套接字 bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); listen(sfd, 64); printf("wait for client connect ... "); clie_addr_len = sizeof(clie_addr); while(1) { //在accept之前休眠10s sleep(10); //阻塞等待客户端发起连接 cfd = accept(sfd, (struct sockaddr *)&clie_addr, &clie_addr_len); //打印accept后的信息和客户端的连接 if(cfd > 0) { printf("accept cfd = %d " , cfd); } printf("client IP:%s port:%d ", inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)), ntohs(clie_addr.sin_port)); //服务端读取数据 len = read(cfd, buf, sizeof(buf)); //read返回0说明对端已经关闭 if(len < 0) { //进一步判断是否收到RST if(errno == ECONNRESET) { printf("read reset by peer "); break; } } } close(sfd); close(cfd); return 0; }
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #define SERV_IP "127.0.0.1" #define SERV_PORT 10001 int main(void) { int sfd, len,ret; struct sockaddr_in serv_addr; struct linger lgr; char buf[BUFSIZ]; sfd = socket(AF_INET, SOCK_STREAM, 0); if(ret < 0){ perror("set SO_LINGER Error"); } bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr); serv_addr.sin_port = htons(SERV_PORT); //客户端connect连接返回,通过SO_LINGER选项立刻发送RST lgr.l_onoff = 1; lgr.l_linger = 0; ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr); ret = connect(sfd, (struct sockaddr *)&serv_addr , sizeof(serv_addr)); if(ret == 0) { printf("client connect successful "); } //关闭链接 close(sfd); return 0; }
RST报文
demo2
服务端不变
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #define SERV_IP "127.0.0.1" #define SERV_PORT 10001 int main(void) { int sfd, len,ret; struct sockaddr_in serv_addr; struct linger lgr; char buf[BUFSIZ]; sfd = socket(AF_INET, SOCK_STREAM, 0); if(ret < 0){ perror("set SO_LINGER Error"); } bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr); serv_addr.sin_port = htons(SERV_PORT); //客户端connect连接返回,通过SO_LINGER选项立刻发送RST lgr.l_onoff = 1; lgr.l_linger = 10; ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr); ret = connect(sfd, (struct sockaddr *)&serv_addr , sizeof(serv_addr)); if(ret == 0) { printf("client connect successful "); } //关闭链接 close(sfd); return 0; }
更改l_linger
//客户端connect连接返回,通过SO_LINGER选项立刻发送RST lgr.l_onoff = 1; lgr.l_linger = 1; ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr);
demo3
//客户端connect连接返回,通过SO_LINGER选项立刻发送RST lgr.l_onoff = 0; lgr.l_linger = 1; ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr);
demo4
int main(void) { int sfd, len,ret; struct sockaddr_in serv_addr; struct linger lgr; char buf[BUFSIZ]; sfd = socket(AF_INET, SOCK_STREAM, 0); if(ret < 0){ perror("set SO_LINGER Error"); } bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr); serv_addr.sin_port = htons(SERV_PORT); //客户端connect连接返回,通过SO_LINGER选项立刻发送RST lgr.l_onoff = 1; lgr.l_linger = 10; ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr); ret = connect(sfd, (struct sockaddr *)&serv_addr , sizeof(serv_addr)); if(ret == 0) { printf("client connect successful "); } //关闭链接 close(sfd); write(sfd, "hello", sizeof("hello")); return 0; }