在四次挥手中, 被动关闭的一端进入CLOSE_WAIT状态, 此时, 如果还在这个socket上发送数据, 那么主动关闭(这是说的是close关闭, 而非shundown关闭, 他们有区别, 我们后面再说)的一端会返回RST.
我们来看看:
服务端程序为:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
int main()
{
int sockSrv = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addrSrv;
addrSrv.sin_family = AF_INET;
addrSrv.sin_addr.s_addr = INADDR_ANY;
addrSrv.sin_port = htons(8765);
bind(sockSrv, (const struct sockaddr *)&addrSrv, sizeof(struct sockaddr_in));
listen(sockSrv, 5);
struct sockaddr_in addrClient;
int len = sizeof(struct sockaddr_in);
int sockConn = accept(sockSrv, (struct sockaddr *)&addrClient, (socklen_t*)&len);
while(1)
{
char szRecvBuf[50001] = {0};
int iRet = recv(sockConn, szRecvBuf, sizeof(szRecvBuf) - 1, 0);
printf("iRet is %d\n", iRet);
getchar();
close(sockConn);
}
while(1);
close(sockSrv);
return 0;
}
先启动它。
客户端程序为:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
int main()
{
int sockClient = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addrSrv;
addrSrv.sin_addr.s_addr = inet_addr("10.100.70.140");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8765);
connect(sockClient, ( const struct sockaddr *)&addrSrv, sizeof(struct sockaddr_in));
while(1)
{
#define N 200
char szSendBuf[N] = {0};
for(unsigned int i = 0; i < N; i++) //字符数组最后一个字符不要求是‘\0’
{
szSendBuf[i] = 'a';
}
int iRet = send(sockClient, szSendBuf, sizeof(szSendBuf) , 0);
printf("send size is %d, iRet is %d\n", sizeof(szSendBuf), iRet);
getchar();
}
close(sockClient);
return 0;
}
再启动它。
三次握手建立后, 客户端给服务端正常发送数据。 服务端接受到数据后, 调用close来主动关闭链接, 此时客户端进入CLOSE_WAIT状态, 如果客户端继续在这个socket上发送数据, 那么服务端给回RST包, 看看结果:
xxxxxx$ ./server
iRet is 200 第一次收200字节
iRet is -1 socket已经关闭,所以本次recv返回-1
xxxxxx$ netstat -nao | grep 8765
tcp 0 0 10.100.70.139:41849 10.100.70.140:8765 ESTABLISHED off (0.00/0/0) 三次握手后的状态
xxxxxx$
xxxxxx$
xxxxxx$
xxxxxx$ netstat -nao | grep 8765
tcp 1 0 10.100.70.139:41849 10.100.70.140:8765 CLOSE_WAIT off (0.00/0/0) 服务端主动关链接后客户端socket的状态
xxxxxx$ ./client
send size is 200, iRet is 200 第一次发送200字节
send size is 200, iRet is 200 变成CLOSE_WAIT后, 继续发送200字节
21:21:52.595187 IP 10.100.70.139.41849 > 10.100.70.140.ultraseek-http: Flags [P.], seq 201:401, ack 2, win 56, options [nop,nop,TS val 1559812393 ecr 1559808982], length 200
0x0000: 4500 00fc 80ef 4000 4006 172e 0a64 468b E.....@.@....dF.
0x0010: 0a64 468c a379 223d aede 4129 a44f 9d3c .dF..y"=..A).O.<
0x0020: 8018 0038 a2cd 0000 0101 080a 5cf8 d929 ...8........\..)
0x0030: 5cf8 cbd6 6161 6161 6161 6161 6161 6161 \...aaaaaaaaaaaa
0x0040: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x0050: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x0060: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x0070: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x0080: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x0090: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x00a0: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x00b0: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x00c0: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x00d0: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x00e0: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa
0x00f0: 6161 6161 6161 6161 6161 6161 0000 0000 aaaaaaaaaaaa....
0x0100: 0000 0000 0000 0000 0000 0000 ............
21:21:52.595378 IP 10.100.70.140.ultraseek-http > 10.100.70.139.41849: Flags [R], seq 2756681020, win 0, length 0
0x0000: 4500 0028 a2a2 4000 4006 f64e 0a64 468c E..(..@.@..N.dF.
0x0010: 0a64 468b 223d a379 a44f 9d3c 0000 0000 .dF."=.y.O.<....
0x0020: 5004 0000 06bf 0000 0000 0000 0000 0000 P...............
0x0030: 0000 0000 0000 0000 ........
我们见到RST了, 很容易理解, 服务端都已经发出FIN表示请求关闭了, 你客户端还发数据过去, 有意义么? 直接给你RST