Linux网络编程二(TCP图解三次握手及四次挥手、TCP滑动窗口、MSS、TCP状态转换、多进程/多线程服务器实现)

news2024/11/24 16:53:27

文章目录

      • 1、TCP三次握手
        • (1) 第一次握手
        • (2) 第二次握手
        • (3) 第三次握手
      • 2、TCP四次挥手
        • (1) 一次挥手
        • (2) 二次挥手
        • (3) 三次挥手
        • (4) 四次挥手
      • 3、TCP滑动窗口
      • 4、TCP状态时序图
      • 5、多进程并发服务器
      • 6、多线程并发服务器

1、TCP三次握手

TCP三次握手(TCP three-way handshake)是TCP协议建立可靠连接的过程,确保客户端和服务器之间可以进行可靠的通信。下面是TCP三次握手的详细过程
假设客户端为A,服务器为B。

SYN---> ACK + SYN --->ACK
(1) 第一次握手

第一次握手(SYN=1,seq=500)
A向B发送一个带有SYN标志位的数据包,表示A请求建立连接。SYN标志位为1表示这是一个连接请求数据包,500是A随机选择的初始序列号。

(2) 第二次握手

第二次握手(SYN=1,ACK=1,ack=500+1,seq=800):
B接收到A发送的连接请求后,会向A回复一个数据包。该数据包中,SYN和ACK标志位都被设置为1。ACK=1表示B确认收到了A的连接请求,ack字段的值为A的初始序列号加1,表明B期望下一个收到的序列号是A初始序列号加1。seq字段800是B随机选择的初始序列号。

(3) 第三次握手

第三次握手(ACK=1,ack=800+1):
A收到B的回复后,检查ACK标志位是否为1,以及ack字段的值是否为B的初始序列号加1。如果正确,A会向B发送一个确认数据包。在该数据包中,ACK标志位被设置为1,表示A确认收到了B的回复。ack字段的值是B的初始序列号加1,表明A期望下一个收到的序列号是B初始序列号加1。
完成这三次握手后,TCP连接就建立成功,A和B之间可以开始传输数据。连接的状态变为已建立(ESTABLISHED)。
三次握手是操作系统内核(Kernel)的TCP协议栈负责处理。用户层的表现:服务器端是accept(),客户端是connect(),其这两个函数成功执行并返回了。
自创

2、TCP四次挥手

TCP四次挥手(TCP four-way handshake)是TCP连接的关闭过程,用于在客户端和服务器之间终止一个已建立的连接。与TCP三次握手不同,四次挥手需要进行四个步骤来关闭连接,以确保数据传输的完整性和可靠性。

FIN--->ACK   FIN--->ACk
(1) 一次挥手

客户端向服务器发送连接释放请求(FIN)的数据包。
客户端希望关闭连接,因此发送一个带有FIN标志位的数据包,FIN=1表示连接释放请求。设置序列号为seq=501。

(2) 二次挥手

服务器接收到客户端的连接释放请求后,回复确认连接释放(ACK)的数据包。
服务器收到客户端的FIN后,发送一个带有ACK标志位的数据包,ACK=1,ack 502表示确认收到客户端的连接释放请求。

(3) 三次挥手

服务器向客户端发送连接释放请求(FIN)的数据包。
服务器希望关闭连接,因此发送一个带有FIN标志位的数据包,FIN=1表示连接释放请求。设置序列号为seq=701。

(4) 四次挥手

客户端接收到服务器的连接释放请求后,回复确认连接释放(ACK)的数据包。
客户端收到服务器的FIN后,发送一个带有ACK标志位(这个不是数据,是控制报文),ACK=1,ack 702表示确认收到服务器的连接释放请求。
在发送完ACK后,客户端等待一段时间,确保服务器收到了ACK,然后完全关闭连接。

3、TCP滑动窗口

TCP滑动窗口是TCP协议中的一个重要概念,用于实现流量控制可靠性传输。滑动窗口机制允许发送方和接收方在数据传输过程中动态调整可发送和可接收的数据量,从而适应不同的网络条件和接收方的处理能力。每次通信时,接收方利用win(4096)告知发送方缓冲区剩余大小。
MSS(Maximum Segment Size)是指TCP数据包中的最大有效载荷大小,它表示在TCP协议中一次性发送的最大数据量(即数据包中的有效数据部分,不包括TCP头部和IP头部)。
在TCP连接建立时,通过TCP三次握手的过程中,双方会交换彼此的MSS值,然后根据两端通信的网络链路的MTU大小进行协商,确定实际使用的MSS。

MSS = 1500 - 20 (TCP头部) - 20 (IP头部) = 1460 字节

这意味着在该TCP连接中,一次可以发送的最大有效数据量为1460字节,超过这个大小的数据将被拆分成多个TCP数据包进行传输。
MSS的设置对于TCP性能和网络吞吐量很重要。合理设置MSS可以避免网络分段和数据重组,提高数据传输效率,特别是在一些高延迟、低带宽的网络环境中。

4、TCP状态时序图

使用命令查看状态

netstat -aptn | grep 端口号  #查看tcp端口
netstat -apn | grep 端口号  #查看tcp、udp端口

1、主动发起连接请求端
CLOSE----发送 SYN—SYN_SEND—接收 ACK、SYN—发送 ACK-ESTABLISHED(数据通信态)

2、主动关闭连接请求端
ESTABLISHED(数据通信态)—发送 FIN—FIN_WAIT_1 --接收 ACK --FIN_WAIT_2(半关闭)—接收对端发送 FIN—FIN_WAIT_2(半关闭)—回发ACK–TIME_WAIT(只有主动关闭连接方,会经历该状态)—等2MSL时长—CLOSE

3、被动接收连接请求端
CLOSE—LISTEN—接收 SYN—LISTEN—发送 ACK、SYN—SYN_RCVD—接收ACK—ESTABLISHED(数据通信态)

4、被动关闭连接请求端
ESTABLISHED(数据通信态)—接收 FIN —ESTABLISHED(数据通信态)— 发送ACK — CLOSE_WAIT(说明对端【主动关闭连接端】处于FIN_WAIT_2(半关闭)状态—发送FIN —LAST_ACK—接收ACK—CLOSE
重点:ESTABLISHED(数据通信态)、FIN_WAIT_2、CLOSE_WAIT、TIME_WAIT(2MSL).
在这里插入图片描述
先启动服务器,只有LISTEN状态。
在这里插入图片描述
启动客户端,此时三次握手建立完成,进入ESTABLISHED(数据通信态)。
在这里插入图片描述
尝试关闭一个客户端,此时该客户端进入TIME_WAIT状态。
在这里插入图片描述
服务器先主动关闭,服务器进入FIN_WAIT_2(半关闭)状态。客户端进入CLOSE_WAIT状态。
在这里插入图片描述
此时迅速关闭客户端,客户端处于TIME_WAIT状态。
在这里插入图片描述
提示:#include "wrap.h"错误处理函数,已经封装
错误处理函数

5、多进程并发服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include "wrap.h"				//错误处理函数,已经封装
								//https://blog.csdn.net/qq_45009309/article/details/131813756?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171204506416800184170823%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171204506416800184170823&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-131813756-null-null.nonecase&utm_term=%E9%94%99%E8%AF%AF&spm=1018.2226.3001.4450
#define SRV_PORT 9999

void catch_child(int signum)		//回调函数 内核操作 产生信号后进来
{
	while(waitpid(0, NULL, WNOHANG) > 0);	 //非阻塞回收子进程
											//循环回收是因为可能产生多个子进程死亡
	return ;				
}

int main(int argc, char* argv[])
{
	int lfd, cfd;								
	pid_t pid;
	int ret;
	char buf[BUFSIZ];
	struct sockaddr_in srv_addr, clt_addr;
	socklen_t clt_addr_len;

	//memset(&srv_addr, 0, sizeof(srv_addr));				//地址结构清零
	bzero(&srv_addr, sizeof(srv_addr));

	srv_addr.sin_family = AF_INET;							
	srv_addr.sin_port = htons(SRV_PORT);
	srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	lfd = Socket(AF_INET, SOCK_STREAM, 0);		//创建套接字 返回用于监听的文件描述符

	Bind(lfd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));	//绑定服务器IP+地址

	Listen(lfd, 128);							//设置监听上线
	clt_addr_len = sizeof(clt_addr);

	while (1) {
		
		cfd = Accept(lfd, (struct sockaddr*)&clt_addr, &clt_addr_len);	//返回用于双方通信的文件描述符

		pid = fork();							//创建子进程
		if (pid < 0) {
			perr_exit("fork error");
		}
		else if (pid == 0) {
			close(lfd);
			break;
		}
		else {									//父进程使用信号捕捉回收子进程
			struct sigaction act;
			act.sa_handler = catch_child;
			sigemptyset(&act.sa_mask);
			act.sa_flags = 0;

			ret = sigaction(SIGCHLD, &act, NULL);
			if (ret != 0) {
				perr_exit("sigaction error");
			}
			close(cfd);
			continue;
		}
	}

	if (pid == 0) {								//子进程实现读写功能
		for (;;) {
			ret = Read(cfd, buf, sizeof(buf));
			for (int i = 0; i < ret; i++) {
				buf[i] = toupper(buf[i]);

			}
			write(cfd, buf, ret);
			write(STDOUT_FILENO, buf, ret);		//实现大小写转换功能

			if (ret == 0) {
				close(cfd);
				exit(1);
			}
		}
	}
	return 0;
}

在这里插入图片描述

6、多线程并发服务器

//头文件同上

#define MAXLINE 8192
#define SERV_PORT 8000

struct s_info {							//定义一个结构体,将地址结构跟cfd捆绑
	struct sockaddr_in cliaddr;		
	int connfd;
};

void* do_work(void* arg)				//子线程主调函数
{
	int n, i;
	struct s_info* ts = (struct s_info*)arg;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];			//16

	while (1) {
		n = Read(ts->connfd, buf, MAXLINE);
		if (n == 0) {
			printf("the client %d closed...\n", ts->connfd);
			break;
		}
		printf("received from %s at PORT %d\n",			//打印客户端IP+端口
			inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
			ntohs((*ts).cliaddr.sin_port));

		for (i = 0; i < n; i++)
			buf[i] = toupper(buf[i]);

		Write(STDOUT_FILENO, buf, n);
		Write(ts->connfd, buf, n);					//回写到客户端
	}
	Close(ts->connfd);
	return (void*)0;
}

int main(int argc, char* argv[])
{
	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int listenfd, connfd;
	pthread_t tid;

	struct s_info ts[256];		//创建结构体数组
	int i = 0;

	listenfd = Socket(AF_INET, SOCK_STREAM, 0);			//创建一个socket,得到lfd
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(SERV_PORT);				//指定端口号
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);		//指定本地任意IP

	Bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));	//绑定
	Listen(listenfd, 128);

	printf("Accepting client connect...\n");

	while (1) {
		cliaddr_len = sizeof(cliaddr);
		connfd = Accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddr_len);		//阻塞监听客户端链接请求
		ts[i].cliaddr = cliaddr;
		ts[i].connfd = connfd;

		pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
		pthread_detach(tid);							//子线程分离,防止僵尸线程产生
		i++;
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1564592.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

玩转ChatGPT:Kimi测评(科研写作)

一、写在前面 ChatGPT作为一款领先的语言模型&#xff0c;其强大的语言理解和生成能力&#xff0c;让无数用户惊叹不已。然而&#xff0c;使用的高门槛往往让国内普通用户望而却步。 最近&#xff0c;一款由月之暗面科技有限公司开发的智能助手——Kimi&#xff0c;很火爆哦。…

Vue3_2024_7天【回顾上篇watch常见的后两种场景】完

随笔&#xff1a;这年头工作不好找咯&#xff0c;大家有学历提升的赶快了&#xff0c;还有外出人多注意身体&#xff0c;没错我在深圳这边阳了&#xff0c;真的绝啊&#xff0c;最尴尬的还给朋友传染了&#xff01;&#xff01;&#xff01; 之前三种的监听情况&#xff0c;监听…

java发送请求-cookie有关代码

在初始化后添加cookie的代码 用这个httpclients类调custom方法&#xff0c;进行代码定制化 找和cookie有关的方法&#xff0c;设置默认的cookie存储信息 入参是接口 将入参粘贴后找方法&#xff0c;用new实现这个接口 这个方法是无参空构造&#xff0c;可以使用 设置了cookie …

Java项目:86 springboot电影评论网站系统设计与实现

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本电影评论网站管理员和用户。 管理员功能有个人中心&#xff0c;用户管理&#xff0c;电影类别管理&#xff0c;电影信息管理&#xff0c;留…

Linux系统---进程间通信与管道入门

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、进程间通信 1.进程间通信的目的 1.数据传输&#xff1a;一个进程需要把他的数据传给另外一个进程。 2.资源共享&…

idea开发 java web 酒店推荐系统bootstrap框架开发协同过滤算法web结构java编程计算机网页

一、源码特点 java 酒店推荐推荐系统是一套完善的完整信息系统&#xff0c;结合java web开发和bootstrap UI框架完成本系统 采用协同过滤算法进行推荐 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式…

Excel列匹配VLookUp功能使用

生活中很多关于excel多列数据进行匹配计算等场景,其中最常用的一个函数就是VLookUp了,下面直接上图: 得到结果如下: 得到结果如下: 注意: 1.在需要把计算完的数据粘贴到另一列或者另个sheet时,复制后,不要直接ctrlv粘贴,这样会把计算公式粘贴到对应的列.正确做法是:右键粘贴,选…

redis 的StringRedisTemplate

6.3 StringRedisTemplate 尽管JSON的序列化方式可以满足我们的需求&#xff0c;但依然存在一些问题&#xff0c;如图&#xff1a; 为了在反序列化时知道对象的类型&#xff0c;JSON序列化器会将类的class类型写入json结果中&#xff0c;存入Redis&#xff0c;会带来额外的内存…

Redis中的复制功能(三)

复制 服务器运行ID 除了复制偏移量和复制积压缓冲区之外&#xff0c;实现部分重同步还需要用到服务器运行ID(run ID): 1.每隔Redis服务器&#xff0c;不论主服务器还是从服务&#xff0c;都会有自己的运行ID2.运行ID在服务器启动时自动生成&#xff0c;由40个随机的十六进制…

基于kmeans的聚类微博舆情分析系统

第一章绪论 1.1研究背景 如今在我们的生活与生产的每个角落都可以见到数据与信息的身影。自从上十世纪八十年代的中后期开始&#xff0c;我们使用的互联网技术已经开始快速发展&#xff0c;近些年来云计算、大数据和物联网等与互联网有相领域的发展让互联网技术达到了史无前例…

浅谈iOS开发中的自动引用计数ARC

1.ARC是什么 我们知道&#xff0c;在C语言中&#xff0c;创建对象时必须手动分配和释放适量的内存。然而&#xff0c;在 Swift 中&#xff0c;当不再需要类实例时&#xff0c;ARC 会自动释放这些实例的内存。 Swift 使用 ARC 来跟踪和管理应用程序的内存&#xff0c;其主要是由…

Vue-Next-Admin:适配手机、平板、PC的开源后台管理模板

摘要&#xff1a;随着移动设备和PC的普及&#xff0c;为了满足不同设备的需求&#xff0c;开发一个能够自适应手机、平板和PC的后台管理系统变得至关重要。本文将介绍一个基于Vue3.x、Typescript、Vite、Element Plus等技术的开源模板库——Vue-Next-Admin&#xff0c;帮助开发…

rust项目组织结构和集成测试举例

概述 在学习rust的过程中&#xff0c;当项目结构略微复杂的时候&#xff0c;写集成测试的时候发现总是不能引用项目中的代码&#xff0c;导致编写测试用例失败。查阅了教程&#xff0c;一般举例都很简单。查阅了谷歌和百度以及ai&#xff0c;也没有找到满意的答案。这里记录一…

Spark-Scala语言实战(10)

在之前的文章中&#xff0c;我们学习了如何在spark中使用RDD的filter,distinct,intersection三种方法。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 Spark-…

Android 窗口那些事儿

目录 1. &#x1f4c2; 前言 你&#xff0c;是否有过这些疑问&#xff1f; 2. &#x1f531; Window 2.1 认识 Window 的几个阶段 1&#xff09;阶段一&#xff1a;Window 约等于 Activity 2&#xff09;阶段二&#xff1a;Window 约等于 View 3&#xff09;阶段三&…

【六 (2)机器学习-机器学习建模步骤/kaggle房价回归实战】

一、确定问题和目标&#xff1a; 1、业务需求分析&#xff1a; 与业务团队或相关利益方进行深入沟通&#xff0c;了解他们的需求和期望。 分析业务流程&#xff0c;找出可能的瓶颈、机会或挑战。 思考机器学习如何帮助解决这些问题或实现业务目标。 2、问题定义&#xff1a;…

Android Studio的Profiler生成trace排查Android冷启动耗时,Kotlin

Android Studio的Profiler生成trace排查Android冷启动耗时&#xff0c;Kotlin 利用AS自带的Profiler抓取trace排查定位冷启动耗时方法&#xff0c;不用写代码&#xff0c;直接配置AS即可完成。 例如下面代码&#xff1a; import android.os.Bundle import androidx.appcompat…

计算机网络-HTTP相关知识-RSA和ECDHE及优化

HTTPS建立基本流程 客户端向服务器索要并验证服务器的公钥。通过密钥交换算法&#xff08;如RSA或ECDHE&#xff09;协商会话秘钥&#xff0c;这个过程被称为“握手”。双方采用会话秘钥进行加密通信。 RSA流程 RSA流程包括四次握手&#xff1a; 第一次握手&#xff1a;客户…

vue3项目运行正常但vscode红色波浪线报错

以下解决办法如不生效&#xff0c;可尝试 重启 vscode 一、Vetur插件检测问题 vetur 是一个 vscode 插件&#xff0c;用于为 .vue 单文件组件提供代码高亮以及语法支持。但 vue 以及 vetur 对于 ts 的支持&#xff0c;并不友好。 1、原因 如下图&#xff1a;鼠标放到红色波浪…

基于单片机和ICL7135多档位数字电压表设计

**单片机设计介绍&#xff0c;基于单片机和ICL7135多档位数字电压表设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机和ICL7135的多档位数字电压表设计是一个结合了硬件与软件技术的综合性项目。这种设计旨在实现一…