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

news2024/12/24 2:30:23

TCP三次握手

TCP三次握手(TCP three-way handshake)是TCP协议建立可靠连接的过程,确保客户端和服务器之间可以进行可靠的通信。下面是TCP三次握手的详细过程:
假设客户端为A,服务器为B
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(),其这两个函数成功执行并返回了。

TCP四次挥手

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

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可以避免网络分段和数据重组,提高数据传输效率,特别是在一些高延迟、低带宽的网络环境中。

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"错误处理函数,已经封装
链接://https://blog.csdn.net/qq_45009309/article/details/131813756?spm=1001.2014.3001.5501

多进程并发服务器

#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?spm=1001.2014.3001.5501

#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;
}

在这里插入图片描述

多线程并发服务器

#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?spm=1001.2014.3001.5501

#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/1148112.html

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

相关文章

【存储】lotusdb的原理及实现

最近看了lotusdb的源码。lotusdb是一个golang实现的嵌入式的持久化kv存储。 从整体设计上看&#xff0c;lotusdb采用了类似LSM树的架构&#xff0c;并采用了针对SSD的优化&#xff0c;将key和value分开存储。在此基础上&#xff0c;lotusdb将LSM树中存储key的SST使用B树或者ha…

进阶JAVA篇-了解 File 文件的常用API

&#x1f525;博客主页&#xff1a; 小扳_-CSDN博客 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 1.0 File 文件的说明 2.0 如何创建 File 类的对象 2.1 需要注意的事项 3.0 File 类的常用 API 3.1 如何创建文件或文件夹 3.2 如何查询文件和文件夹的信息 3.3 如何删除文件和…

鸿蒙系统、澎湃系统和安卓系统的区别一看就懂

前言 最近看了小米澎湃OS的发布会&#xff0c;这是继华为鸿蒙OS脱离Android OS后&#xff0c;国内发布的另一个重量级的操作系统。 依稀记得&#xff0c;当初鸿蒙OS问世的时候&#xff0c;很多人都质疑它是Android OS的套壳&#xff0c;对鸿蒙系统提出了诸多质疑和否定。 现趁着…

ActiveMQ

ActiveMQ 安装 下载网址&#xff1a;ActiveMQ 一定要和自己安装的jdk版本匹配&#xff0c;不然会报错 下载到本地之后解压缩 有可能端口号被占用 解除端口号占用&#xff0c;参考&#xff1a;Windows_端口被占用 打开cmd 查询所有的端口号 netstat -nao查询指定端口号 n…

基于STM32的示波器信号发生器设计

**单片机设计介绍&#xff0c;基于STM32的示波器信号发生器设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序文档 六、 文章目录 一 概要 基于STM32的示波器信号发生器是一种高性能的电子仪器&#xff0c;用于测试和分析电路中的电信号。在该系统中&a…

ZKP7.1 Polynomial Commitments Based on Error-correcting Codes (Background)

ZKP学习笔记 ZK-Learning MOOC课程笔记 Lecture 7: Polynomial Commitments Based on Error-correcting Codes (Yupeng Zhang) Recall: common paradigm for efficient SNARK A polynomial commitment scheme A polynomial interactive oracle proof (IOP) SNARK for gene…

AD9371 官方例程HDL详解之JESD204B RX侧格式配置及各层主要功能

AD9371 系列快速入口 AD9371ZCU102 移植到 ZCU106 &#xff1a; AD9371 官方例程构建及单音信号收发 采样率和各个时钟之间的关系 &#xff1a; AD9371 官方例程HDL详解之JESD204B TX侧时钟生成 &#xff08;三&#xff09; 参考资料&#xff1a; UltraScale Architecture G…

Jenkins git 克隆代码超时问题解决

目录 一、问题描述二、解决方案方式一&#xff1a;手动配置超时时间方式二&#xff1a;浅克隆&#xff08;推荐&#xff09; 一、问题描述 在使用 Jenkins 首次进行服务部署的时候&#xff0c;如果我们项目的 .git 文件夹太大&#xff0c;可能会导致 git clone 失败。 在 Jen…

当『后设学习』碰上『工程学思维』

只要我成为一个废物&#xff0c;就没人能够利用我&#xff01; 雷猴啊&#xff0c;我是一只临期程序猿。打过几年工&#xff0c;写过几行代码。但今天我不想聊代码&#xff0c;我们聊聊学习这件事。 技术年年更新&#xff0c;尤其是前端框架&#xff0c;很多时候觉得学习速度都…

leetcode-栈与队列

C中stack 是容器么&#xff1f; 栈&#xff0c;队列往往不被归类为容器&#xff0c;而被归类为container adapter(容器适配器)。因为由底层的容器实现&#xff0c;同时使用适配器模式的设计模式&#xff0c;封装了一层。 我们使用的stack是属于哪个版本的STL&#xff1f;SGI ST…

【Java 进阶篇】解决Java Web应用中请求参数中文乱码问题

在Java Web应用开发中&#xff0c;处理请求参数时经常会遇到中文乱码的问题。当浏览器向服务器发送包含中文字符的请求参数时&#xff0c;如果不正确处理&#xff0c;可能会导致乱码问题&#xff0c;使得参数无法正确解析和显示。本文将详细探讨Java Web应用中请求参数中文乱码…

微信小程序 php java nodejs python课堂学生考勤签到系统zng1p

课堂考勤也是学校的核心&#xff0c;是必不可少的一个部分。在学校的整个教学行业中&#xff0c;学生担负着最重要的角色。为满足如今日益复杂的管理需求&#xff0c;各类基于微信小程序也在不断改进。本课题所设计的基于微信小程序的课堂考勤系统&#xff0c;使用微信开发者与…

shell中的运算

目录 1.运算符号 2.运算指令 练习 1.运算符号 运算符号意义加法-减法*乘法/除法%除法后的余数**乘方自加一- -自减一<小于<小于等于>大于>大于等于等于ji ->jji*j*i->jj*i/j/i->jj/i%j%i->jj%i 2.运算指令 (()) //((a12))let //let a12 …

JavaScript_Pig Game保存当前分数

上个文章我们基本上完成了摇色子和切换当前玩家的功能。 现在我们开始写用户选择不再摇骰子的话&#xff0c;我们将用户的当前分数存入到持有分数中&#xff01; ● 首先我们应该利用一个数组去存储两个用户的分数 const scores [0, 0];● 接着我们利用数组来对分数进行累…

SHCTF2023 山河CTF Reverse方向[Week1]全WP 详解

文章目录 [WEEK1]ez_asm[WEEK1]easy_re[WEEK1]seed[WEEK1]signin[WEEK1]easy_math[WEEK1]ez_apk [WEEK1]ez_asm 从上往下读&#xff0c;第一处是xor 1Eh&#xff0c;第二处是sub 0Ah&#xff1b;逆向一下先加0A后异或1E 写个EXP data "nhuo[M7mc7uhc$7midgbTf7$7%#ubf7 …

nginx请求时找路径问题

nginx请求时找路径问题 你是否遇到过这样的情况&#xff1a; 当你安装了nginx的时候&#xff0c;为nginx配置了如下的location&#xff0c;想要去访问路径下面的内容&#xff0c;可是总是出现404&#xff0c;找不到文件&#xff0c;这是什么原因呢&#xff0c;今天我们就来解…

OpenAI : GPT-4 发布更新,整合了画图、插件、代码等能力

本心、输入输出、结果 文章目录 OpenAI : GPT-4 发布更新,整合了画图、插件、代码等能力前言GPT-4 的复合能力更新中的 automatic (自动的)获取天气我们看看讯飞星火的表现放大后内容并不是我们想要的我们看看百度文心一言的表现弘扬爱国精神OpenAI : GPT-4 发布更新,整合…

CSS3中的字体和文本样式

CSS3优化了CSS 2.1的字体和文本属性&#xff0c;同时新增了各种文字特效&#xff0c;使网页文字更具表现力和感染力&#xff0c;丰富了网页设计效果&#xff0c;如自定义字体类型、更多的色彩模式、文本阴影、生态生成内容、各种特殊值、函数等。 1、字体样式 字体样式包括类…

画个哆啦A梦吧

可自定义名字 源代码 #!/usr/bin/python # -*- coding:utf-8 -*-# from turtle import * import turtle as t# 无轨迹跳跃 def my_goto(x, y):t.penup()t.goto(x, y

多个相同地址的I2C设备,如何挂载在同一条总线上

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘湖南区域日常实习生&#xff0c;任何区域的暑假Linux驱动实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &#xff08;2&#xff0…