TCP状态转换图-[CLOSE_WAIT状态错误分析和解决方法(网络连接无法释放)]

前言

网络通信一直都是所有的框架的基础

正文

一, TCP状态转换图

虚线:表示服务器的正常状态转换
实线:表示客户端的正常状态转换
应用:表示状态转换在应用进程发起操作时发生
接收:表示状态转换在接收到分节发生
发送:表示这个转换发生什么

二, TCP连接的分组交换

三,CLOSE_WAIT状态出现时机

有一端主动关闭socket链接, 在没有关闭socket链接的一端出现CLOSE_WAIT状态, 主动关闭socket的一端出现了FIN_WAIT_2状态, 在主动关闭socket一端没有收到被动关闭一端的响应会等待73秒后关闭, 而被动关闭有会有大量CLOSE_WAIT状态 的原因是没有关闭socket连接(网络连接无法释放)

1, 服务端有大量CLOSE_WAIT状态, 和客户端FIN_WAIT_2状态的使用

命令

 tcpdump tcp port 80

抓包分析

2, 抓包分析结果

客户发送了FIN 服务端回一个ACK就介绍了

这是服务端的测试的代码测试的代码

	#include	"unp.h"
	#include	<time.h>
	
	int
	main(int argc, char **argv)
	{
		int					listenfd, connfd;
		socklen_t			len;
		struct sockaddr_in	servaddr, cliaddr;
		char				buff[MAXLINE];
		time_t				ticks;
		int 				optval = 1;
	
		listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	
		bzero(&servaddr, sizeof(servaddr));
		servaddr.sin_family      = AF_INET;
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
		servaddr.sin_port        = htons(SERV_PORT);	/* daytime server */
	
		Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
	
		Listen(listenfd, LISTENQ);
		//端口复用
		//端口复用
		setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
	
		for ( ; ; ) {
			len = sizeof(cliaddr);
			connfd = Accept(listenfd, (SA *) &cliaddr, &len);
			printf("connection from %s, port %d\n",
				   Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)),
				   ntohs(cliaddr.sin_port));
	
	        ticks = time(NULL);
	        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
			//休息 了                就没有关闭服务端出现大量的CLOSE_WAIT状态
			sleep(1000);
	        Write(connfd, buff, strlen(buff));
	
			Close(connfd);
		}
	}

客户端的代码

	#include <stdio.h>
	#include <stdlib.h>
	#include <sys/socket.h>
	#include <sys/types.h>
	#include <strings.h>
	#include <unistd.h>
	#include <arpa/inet.h>
	
	#define SERV_PORT 8888
	#define SERV_IP "47.93.31.88"
	#define MAXLINE 1024
	
	
	int main(int argc, char **argv)
	{
		int					sockfd, n;
		char				recvline[MAXLINE + 1];
		struct sockaddr_in	servaddr;
	
	
		if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
			printf("socket error\n");
	
		bzero(&servaddr, sizeof(servaddr));
		servaddr.sin_family = AF_INET;
		servaddr.sin_port   = htons(SERV_PORT);	/* daytime server */
		if (inet_pton(AF_INET, SERV_IP, &servaddr.sin_addr) <= 0)
			printf("inet_pton error for %s\n", SERV_IP);
	
		if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
			printf("connect error\n");
	
		
		close(sockfd);
	
	#if 0
		while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
			recvline[n] = 0;	/* null terminate */
			if (fputs(recvline, stdout) == EOF)
				printf("fputs error\n");
		}
		if (n < 0)
			printf("read error\n");
	#endif 
		exit(0);
	}

服务端的CLOSE_WAIT的状态

客户端FIN_WAIT_2状态

三, 解决上面的问题是 出现大量CLOSE_WAIT状态

原因是被动关闭的一端没有关闭socket连接 导致大量CLOSE_WAIT状态

现在就是关闭服务端socket连接

服务端的代码:

	#include	"unp.h"
	#include	<time.h>
	
	int
	main(int argc, char **argv)
	{
		int					listenfd, connfd;
		socklen_t			len;
		struct sockaddr_in	servaddr, cliaddr;
		char				buff[MAXLINE];
		time_t				ticks;
		int 				optval = 1;
	
		listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	
		bzero(&servaddr, sizeof(servaddr));
		servaddr.sin_family      = AF_INET;
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
		servaddr.sin_port        = htons(SERV_PORT);	/* daytime server */
	
		Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
	
		Listen(listenfd, LISTENQ);
		//端口复用
		//端口复用
		setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
		//地址复用
		setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
	
		for ( ; ; ) {
			len = sizeof(cliaddr);
			connfd = Accept(listenfd, (SA *) &cliaddr, &len);
			printf("connection from %s, port %d\n",
				   Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)),
				   ntohs(cliaddr.sin_port));
	
	        ticks = time(NULL);
	        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
			//sleep(1000);
	        Write(connfd, buff, strlen(buff));
	
			Close(connfd);
		}
	}

效果图:

结语

个人博客地址:https://chensongpoixs.github.io/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值