Skip to content

tcp客户端和服务器区别_深入理解TCP 服务器与客户端

69d4288fd6942aa4f76134252207f74c.png"Python学习开发",一个值得加星标bd15b565e9366556b5cfdd8eb5a69057.png的公众号。

045045d8b068c60de317bc4b6a878604.png

正文共:9239 字 6 图

预计阅读时间:24 分钟

原始链接:https://ciphersaw.github.io/2018/05/23/Python 绝技 —— TCP 服务器与客户端/

0x00 前言

本文先介绍因特网的核心协议 TCP ,再以 Python 的 socket 模块为例介绍网络套接字,最后给出 TCP 服务器与客户端的 Python 脚本,并演示两者之间的通信过程。

0x01 TCP 协议

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接、可靠的、基于字节流的传输层通信协议。

TCP 协议的执行过程分为连接创建(Connection Establishment)数据传送(Data Transfer)连接终止(Connection Termination)三个阶段,其中「连接创建」与「连接终止」分别是耳熟能详的 TCP 协议三次握手(TCP Three-way Handshake)四次挥手(TCP Four-way Handshake),也是理解本文 TCP 服务器与客户端通信过程的两个核心阶段。

为了能更好地理解下述过程,对 TCP 协议头的关键区段做以下几点说明:

  • 报文的功能在 TCP 协议头的标记符(Flags)区段中定义,该区段位于第 104~111 比特位,共占 8 比特,每个比特位对应一种功能,置 1 代表开启,置 0 代表关闭。例如,SYN 报文的标记符为 00000010,ACK 报文的标记符为 00010000,ACK + SYN 报文的标记符为 00010010

  • 报文的序列号在 TCP 协议头的序列号(Sequence Number)区段中定义,该区段位于第 32~63 比特位,共占 32 比特。例如,在「三次握手」过程中,初始序列号 seq 由数据发送方随机生成。

  • 报文的确认号在 TCP 协议头的确认号(Acknowledgement Number)区段中定义,该区段位于第 64~95 比特位,共占 32 比特。例如,在「三次握手」过程中,确认号ack 为前序接收报文的序列号加 1,代表下一次期望接收到的报文序列号。

连接创建

所谓的「三次握手」,即 TCP 服务器与客户端成功建立通信连接必经的三个步骤,共需通过三个报文完成。

一般而言,首先发送 SYN 报文的一方是客户端,服务器则是监听来自客户端的建立连接请求。

Handshake Step 1

客户端向服务器发送 SYN 报文(SYN=1" role="presentation" style="text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); user-select: none; display: inline; transition: none 0s ease 0s; vertical-align: 0px; line-height: normal; height: 1px !important; width: 1px !important; overflow: hidden !important;">SYN=1)请求建立连接。

此时报文的初始序列号为 seq = x ,确认号为ack = 0,发送完毕后,客户端进入 SYN_SENT 状态。

Handshake Step 2

服务器接收到客户端的 SYN 报文后,发送 ACK + SYN 报文(ACK=1,SYN=1)确认客户端的建立连接请求,并也向其发起建立连接请求。

此时报文的序列号为 seq = y,确认号为 ack = x+1,发送完毕后,服务器进入 SYN_RCVD状态。

Handshake Step 3

客户端接收到服务器的 SYN 报文后,发送 ACK 报文(AACK=1" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">CK=1)确认服务器的建立连接请求。

此时报文的序列号为 seq=x+1" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">seq=x+1,确认号为 ack=y+1" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">ack=y+1。发送完毕后,客户端进入 ESTABLISHED 状态;当服务器接收该报文后,也进入了 ESTABLISHED 状态。

至此,「三次握手」过程全部结束,TCP 通信连接成功建立。

读者可参照以下「三次握手」的示意图进行理解:

75c85605d8343adb4a191d05951c5097.png

连接终止(Connection Termination)

所谓的「四次挥手」,即 TCP 服务器与客户端完全终止通信连接必经的四个步骤,共需通过四个报文完成。

由于 TCP 通信连接是全双工的,因此每个方向的连接可以单独关闭,即可视为一对「二次挥手」,或一对单工连接。主动先发送 FIN 报文的一方,意味着想要关闭到另一方的通信连接,即在此方向上不再传输数据,但仍可以接收来自另一方传输过来的数据,直到另一方也发送 FIN 报文,双方的通信连接才完全终止。

注意,首先发送 FIN 报文的一方,既可以是客户端,也可以是服务器。下面以客户端先发起关闭请求为例,对「四次挥手」的过程进行讲解。

Handshake Step 1

当客户端不再向服务器传输数据时,则向其发送 FIN 报文(FIN=1" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">FIN=1)请求关闭连接。

此时报文的初始序列号为 seq = u ,确认号为ack = 0,(若此报文中 ACK=1" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">ACK=1,则 ACK 的值与客户端的前序接收报文有关)。发送完毕后,客户端进入 FIN_WAIT_1 状态。

Handshake Step 2

服务器接收到客户端的 FIN 报文后,发送 ACK 报文(ACK = 1)确认客户端的关闭连接请求。

此时报文的序列号为 seq = v, 确认号为ack = u + 1,发送完毕后,服务器进入 CLOSE_WAIT 状态;当客户端接收该报文后,进入 FIN_WAIT_2 状态。

注意,此时 TCP 通信连接处于半关闭状态,即客户端不再向服务器传输数据,但仍可以接收服务器传输过来的数据。

Handshake Step 3

当服务器不再向客户端传输数据时,则向其发送 FIN + ACK 报文(FIN=1,ACK=1)请求关闭连接。

此时报文的序列号为 sseq=w" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">eq = w(若在半关闭状态,服务器没有向客户端传输过数据,则 sseq=v+1" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">eq = v+1 ),确认号为 ack = u+1。发送完毕后,服务器进入 LAST_ACK 状态。

Handshake Step 4

客户端接收到服务器的 FIN + ACK 报文后,发送 ACK 报文(ACK = 1)确认服务器的关闭连接请求。

此时报文的序列号为 seq=u+1" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">seq=u+1,确认号为 ack=w+1" role="presentation" style="display: inline; line-height: normal; text-align: left; word-spacing: normal; overflow-wrap: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial;">ack=w+1。发送完毕后,客户端进入 TIME_WAIT 状态;当服务器接收该报文后,进入 CLOSED 状态;当客户端等待了 2MSL 后,仍没接到服务器的响应,则认为服务器已正常关闭,自己也进入 CLOSED 状态。

至此,「四次挥手」过程全部结束,TCP 通信连接成功关闭。

读者可参照以下「四次挥手」的示意图进行理解:

555b8cf6f7f07b6e1cc67e9da95a2266.png

0x02 Network Socket

Network Socket(网络套接字)是计算机网络中进程间通信的数据流端点,广义上也代表操作系统提供的一种进程间通信机制。

进程间通信(Inter-Process Communication,IPC)的根本前提是能够唯一标示每个进程。在本地主机的进程间通信中,可以用 PID(进程 ID)唯一标示每个进程,但 PID 只在本地唯一,在网络中不同主机的 PID 则可能发生冲突,因此采用「IP 地址 + 传输层协议 + 端口号」的方式唯一标示网络中的一个进程。

小贴士:网络层的 IP 地址可以唯一标示主机,传输层的 TCP/UDP 协议和端口号可以唯一标示该主机的一个进程。注意,同一主机中 TCP 协议与 UDP 协议的可以使用相同的端口号。

所有支持网络通信的编程语言都各自提供了一套 socket API,下面以 Python 3 为例,讲解服务器与客户端建立 TCP 通信连接的交互过程:

17df272dd9605ec0cec97ab91c61da97.png

脑海中先对上述过程产生一定印象后,更易于理解下面两节 TCP 服务器与客户端的 Python 实现。

0x03 TCP 服务器

1

版权声明:本文为weixin_34034295原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

深圳SEO优化公司大芬百度竞价包年推广观澜网站改版横岗建设网站松岗优化福永网站推广方案福田网站推广系统观澜seo网站推广惠州关键词排名南山外贸网站设计南澳网站搜索优化爱联至尊标王盐田网站优化按天收费光明至尊标王龙华关键词排名包年推广东莞网站推广系统平湖网页设计福永网站优化推广横岗网站搭建吉祥网站优化按天收费爱联关键词按天扣费大浪营销网站石岩百度标王福田seo网站优化坪地推广网站大浪seo网站推广坪山网络营销大芬网页设计罗湖关键词排名包年推广沙井英文网站建设木棉湾百搜标王歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化