UNIX网络编程:1,传输层简介_honky-tonk_man的博客-程序员秘密

技术标签: linux网络编程  第一部分:UNIX网络编程-传输层简介  

1.0tcp/udp简介

1.1 tcp

tcp是一个面向连接的协议,为用户进程提供可靠的全双工字节流,tcp套接字是一种流套接字(stream socket),tcp关心确认,超时,重传之类的细节,tcp可以用到ipv4也可以用到ipv6

tcp不同于udp的是,

  • tcp首先为服务器和客户之间提供连接,然后再跨连接交换数据,最后终止连接,tcp也提供可靠性,可靠性体现在,当一段向另一端发送数据时,他要求对端返回一个确认,如果没有收到,tcp将自动重传数据并且等待更长时间,在数次重传失败后,tcp才放弃
    tcp还含有用于动态估算客户和服务器之间的往返时间(rtt)的算法,以便它知道等待一个确认需要多少时间。
  • tcp还通过其中每个字节关联一个序列号对所发送的数据进行排序,假设我们有一个应用写2048字节到tcp套接字,导致tcp套接字发送2个分节,第一个分节序列号1~ 1024,第二个分节序列号为2 ~2048 (分节时tcp往下传输给ip的数据单元),如果这些分节按照非顺序到达,接收端的tcp将会为他们重新排序,再把结果数据单元传给应用,如果对端tcp套接字收到重复数据,它可以根据序列号判定数据是重复的,从而丢弃重复数据,

udp不提供可靠性,udp本身不提供确认,序列号,rtt估算,超时和重传等机制,如果一个udp数据报在网络中被复制(有可能堵塞,等其他原因让客户端重传),2个副本都有可能到达接收端的主机,如果udp发送2个被分割的数据报到对端,有可能被排成网络序列,顺序颠倒发送到对端,所以我们使用udp一定要应对这个情况

  • tcp还提供流量控制的功能,这个流量控制的意思就是tcp接收端总是能告知tcp发送端我本地的接收缓存大小,也就是自己还能接收多少字节的数据,这个叫做通告窗口,这样,tcp发送端根据通告窗口发送数据就不会让接收端缓冲区溢出,当缓冲区接收发送端发送的数据后,通告窗口就会变小(因为缓冲区被填上数据),当应用从缓冲区提取数据到应用后,通告窗口变大(缓冲区数据被提取),如果tcp某个套接字的通告窗口满了,发送端只能等待,应用读取数据,使缓冲区空闲后再发送数据进来
  • tcp还是全双工的,代表给定的连接上可以同时发送和传输数据(udp也是可以的)

1.2 udp

udp是一个无连接协议,udp套接字是一种数据报套接字,udp数据报不能保证最终到达他们的目的地,于tcp一样,udp即可使用ipv4也可使用ipv6.

首先我们一个应用程序往UDP套接字写入一个消息,然后这个消息被封装到一个UDP的报文头部(里面有源端口目标端口,用户包长度,checksum),然后这个包再往下被封装ip头部(源ip,目标ip),再往下被封装以太网帧头部(源mac 目标mac),再被传输到对端的主机
UDP不保证UDP报文传输会到达最终目的地,不保证各个数据报的先后顺序跨网络后保持不变,也不保证每个数据只到达一次
如果一个UDP数据包到达了对端主机,但是校验发生错误,或者传输过程中丢了,他就无法传递给对端udp套接字,也不会重传,
我们也说udp是无连接的,因为UDP客户端与服务器之间不必存在任何长期关系,换句话说,一个UDP客户端可以创建一个套接字并且发送一个数据报给一个给定的服务器,然后立即用同一个套接字发送另一个数据报给另一个服务器,同样,一个UDP服务器可以用 同一个UDP套接字从若干个不同UDP客户端接收数据报,每个客户端一个数据报

2.0 TCP三次握手

在这里插入图片描述
1.我们的服务器通过socket创建套接字后,再用bind绑定端口,再用listen监听套接字(这个不是三次握手里面的,他只是准备程序,使客户端连接我们服务端收得到)
2,客户端首先通过connect函数发起主动连接,通常客户端会发送一个SYN(同步)分节,他会告诉服务端他自己的初始序列号,通常syn不懈怠数据,ip报文也就包含一个ip首部和tcp首部,有可能包含tcp option(注意connect的时候是被阻塞的,直到对方服务端accept函数抽取连接后返回确认值到本套接字才会接触堵塞)
3,这一步的意义是服务器确认客户端发送的ACK(使用accept()函数接收客户端发送的连接,接收完成后还会发送一个syn向客户端说自己已经接收好了,在客户端回复收到之前accept都是堵塞的),服务端怎么确认了?首先把客户端发送的SYN+1后的数当成ACK发送回客户端,并且携带一个自己定义的SYN初始序列号,发送给客户端
4,客户端收到服务端发送的ACK核对是否是自己之前发的加一,并且接收客户端自己的SYN,然后说明服务端套接字已经收到自己的连接,然后解除connect的堵塞状态,然后将服务端发送的SYN+1当成ACK返回给服务端,说明自己已经收到,可以进行数据通信
5,最后服务端调用read函数读取数据,读取过程堵塞。

2.1 tcp选项

首先我们每一个syn都有多个tcp选项

2.2 TCP四次挥手

在这里插入图片描述
这里的过程也非常的简单
1,首先客户端调用close()函数主动的关闭连接,调用的时候会发送一个FIN给服务端,表示客户端的数据发送完毕,我要断开链接了
2,服务端收到这个FIN后知道客户端没有数据要发送勒,他就发送一个EOF到发送到应用程序的队列中,等到数据传送完成后再传输EOF给应用程序表示再无任何数据可以接收,并且发送一个ack给服务端,代表自己已经接收这个ack的值就是接收FIN的值+1
3,服务端的应用程序收到EOF后同样调用close()关闭自己的套接字,关闭后也会向客户端发送一个FIN
4,客户端收到FIN后也会发送一个ACK给服务端,来确认自己已经收到,ACK的值也是FIN+1

此处有一个TCP的状态转换图如下
在这里插入图片描述
上半部分是TCP三路握手过程的状态变迁,下半部分是TCP四次挥手过程的状态变迁。

1.CLOSED:起始点,在超时或者连接关闭时候进入此状态,这并不是一个真正的状态,而是这个状态图的假想起点和终点。

2.LISTEN:服务器端等待连接的状态。服务器经过 socket,bind,listen 函数之后进入此状态,开始监听客户端发过来的连接请求。此称为应用程序被动打开(等到客户端连接请求)。

3.SYN_SENT:第一次握手发生阶段,客户端发起连接。客户端调用 connect,发送 SYN 给服务器端,然后进入 SYN_SENT 状态,等待服务器端确认(三次握手中的第二个报文)。如果服务器端不能连接,则直接进入CLOSED状态。

4.SYN_RCVD:第二次握手发生阶段,跟 3 对应,这里是服务器端接收到了客户端的 SYN,此时服务器由 LISTEN 进入 SYN_RCVD状态,同时服务器端回应一个 ACK,然后再发送一个 SYN 即 SYN+ACK 给客户端。状态图中还描绘了这样一种情况,当客户端在发送 SYN 的同时也收到服务器端的 SYN请求,即两个同时发起连接请求,那么客户端就会从 SYN_SENT 转换到 SYN_REVD 状态。

5.ESTABLISHED:第三次握手发生阶段,客户端接收到服务器端的 ACK 包(ACK,SYN)之后,也会发送一个 ACK 确认包,客户端进入 ESTABLISHED 状态,表明客户端这边已经准备好,但TCP 需要两端都准备好才可以进行数据传输。服务器端收到客户端的 ACK 之后会从 SYN_RCVD 状态转移到 ESTABLISHED 状态,表明服务器端也准备好进行数据传输了。这样客户端和服务器端都是 ESTABLISHED 状态,就可以进行后面的数据传输了。所以 ESTABLISHED 也可以说是一个数据传送状态。

上面就是 TCP 三次握手过程的状态变迁。结合第一张三次握手过程图,从报文的角度看状态变迁:SYN_SENT 状态表示已经客户端已经发送了 SYN 报文,SYN_RCVD 状态表示服务器端已经接收到了 SYN 报文。


下面看看TCP四次挥手过程的状态变迁。结合第一张四次挥手过程图来理解。

1.FIN_WAIT_1:第一次挥手。主动关闭的一方(执行主动关闭的一方既可以是客户端,也可以是服务器端,这里以客户端执行主动关闭为例),终止连接时,发送 FIN 给对方,然后等待对方返回 ACK 。调用 close() 第一次挥手就进入此状态。

2.CLOSE_WAIT:接收到FIN 之后,被动关闭的一方进入此状态。具体动作是接收到 FIN,同时发送 ACK。之所以叫 CLOSE_WAIT 可以理解为被动关闭的一方此时正在等待上层应用程序发出关闭连接指令。前面已经说过,TCP关闭是全双工过程,这里客户端执行了主动关闭,被动方服务器端接收到FIN 后也需要调用 close 关闭,这个 CLOSE_WAIT 就是处于这个状态,等待发送 FIN,发送了FIN 则进入 LAST_ACK 状态。

3.FIN_WAIT_2:主动端(这里是客户端)先执行主动关闭发送FIN,然后接收到被动方返回的 ACK 后进入此状态。

4.LAST_ACK:被动方(服务器端)发起关闭请求,由状态2 进入此状态,具体动作是发送 FIN给对方,同时在接收到ACK 时进入CLOSED状态。

5.CLOSING:两边同时发起关闭请求时(即主动方发送FIN,等待被动方返回ACK,同时被动方也发送了FIN,主动方接收到了FIN之后,发送ACK给被动方),主动方会由FIN_WAIT_1 进入此状态,等待被动方返回ACK。

6.TIME_WAIT:从状态变迁图会看到,四次挥手操作最后都会经过这样一个状态然后进入CLOSED状态。共有三个状态会进入该状态

  • 由CLOSING进入:同时发起关闭情况下,当主动端接收到ACK后,进入此状态,实际上这里的同时是这样的情况:客户端发起关闭请求,发送FIN之后等待服务器端回应ACK,但此时服务器端同时也发起关闭请求,也发送了FIN,并且被客户端先于ACK接收到。

  • 由FIN_WAIT_1进入:发起关闭后,发送了FIN,等待ACK的时候,正好被动方(服务器端)也发起关闭请求,发送了FIN,这时客户端接收到了先前ACK,也收到了对方的FIN,然后发送ACK(对对方FIN的回应),与CLOSING进入的状态不同的是接收到FIN和ACK的先后顺序。

  • 由FIN_WAIT_2进入:这是不同时的情况,主动方在完成自身发起的主动关闭请求后,接收到了对方发送过来的FIN,然后回应 ACK。

tcp状态图借鉴于https://blog.csdn.net/yeswenqian/article/details/40110703

2.3 TIME_WAIT状态

为什么要有TIME_WAIT?我们从2个方面说
1,我们的四次挥手后主动发起关闭的一方会进入TIME_WAIT状态,去等待2个MSL,因为主动关闭方发送的最后一个ACK没有传递到服务端(也许因为中间的路由器down了,链路断了),服务端将不断地重新发送他最后一个fin给主动关闭端,如果没有TIME_WAIT这个状态来保持接收的状态,那么将收不到服务端重复发送的FIN
2,还有一个情况就是服务端发送一个连接后立马,关闭了这个socket,又新开了一个socket,目标ip,端口号都一样,那么他老的FIN在网络中迷路了,没有快速发到主动关闭端(客户端),而服务端又发送了一个新的连接,此时TCP将不会给客户端处于TIME_WAIT状态的接口接收新的连接,如果经过2个MSL后老的FIN还没有到达客户端,那么客户端将取消TIME_WAIT状态,老的报文也会在链路中消失,因为传输最大的时间是2个MSL

3.0 端口号

如果一个进程想和服务相联系,他必须找到对端服务的端口,传输层中任何一种协议都有16bit unsigned int 的端口号,不管是tcp还是udp还是sctp,IANA维护着端口号分配列表清单如下

  • 0——1023

    此端口为众所周知的端口,都由IANA分配喝控制,可能的话相同端口号分配给TCP/UDP同一给定的服务,例如不管是udp80还是tcp80都被分配给了web服务器,尽管实现普遍都是用tcp,注意这些总所周知的端口分配必须要有超级用户权限

  • 1024——49151

    这个范围的端口是已登记的端口,这些端口不受IANA控制,不过由IANA登记,并提供他们的使用清单,可能的话这些相同的服务有可能分配给不同协议同一端口号

  • 49152——65535

    这个范围的端口是私有端口,IANA不会去管辖这些端口,他就是我们的临时端口比如我们的web服务器的客户端(浏览器)的端口就是在这个范围,49152正好又是65536的四分之三

3.1 套接字对

一个tcp的套接字对是定义该连接的2个端点的四元组:本地ip地址,本地TCP端口号,目的ip地址,目的端口号,通常表示每个端点的2个值,ip地址和端口号被称为套接字

4.0 tcp端口号于并发连接服务器

当我们的客户端发送一个连接给我们的服务端,服务端的服务主进程会fork一个自身的副本(子进程),让子进程来处理这个请求 ,如下图
在这里插入图片描述
然后我们的客户端还有另一个应用需要连接服务器的21端口,此时客户的主机会为自己分配另一个临时端口比如1501,,然后发送到了服务端,服务端又会fork一个子程序去处理此请求,2个进程处理的已连接套接字都不一样
在这里插入图片描述

notes:tcp无法通过查看目的端口来分离外来的分节到不同端点(那个请求发给那个子进程处理),他是通过比对套接字所有4元素才能确定那个端点接收某个到达的分节,就如上图所示,源端口为1500的被分配到子进程1,源端口为2的被分配到子进程2,其他目的端口为21的tcp分节会被发往服务器(主进程,由主进程来fork一个子进程接收)

4.1 缓冲区大小的限制

首先我们ipv4数据报最大的是65535字节(包括ipv4首部),因为标识ipv4长度的字段有16位
ipv6的报文长度为65575字节,因为标识ipv6的报文长度有16位最大表示65535个字节,但是他这个65535不包含40个字节的ipv6头部(ipv4包括),所以一共是65575个字节,我们可以使用Jumbo Payload选项给ipv6报文扩展到32位(不包括ipv6头部),这个需要我们在链路中设置mtu。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37026934/article/details/102720370

智能推荐

CNN+Depth estimation_depth estimation no pooling_lemianli的博客-程序员秘密

1 - AlexNet 和 VGG-NetCVPR 2015 基本是 “the year of deep learning”,有大概70%的文章是关于deep learning的。大会请来了2位 keynote speakers: 计算机学家 Yann LuCun (NYU, Facebook) 和 心理学家、神经学家 Jack Gallan (Berkeley)。 Yann是公认的 Co

8.muduo学习笔记之base_CurrentThread.{h&cc}_PartnerLv的博客-程序员秘密

1. 说明这是一个命名空间,不是类主要是线程类和异常类中需要用到这个命名空间,异常类需要stackTrace()看函数栈信息,线程类需要其他的一些功能不明白为什么特意分个命名空间,不懂为啥不把这些需要的直接写到线程类中2. 变量说明以下所有变量都是__thread修饰的,这样的变量是线程局部存储的,也就是说每个线程都有个独立的变量t_cachedTid线程真实pid缓存...

零基础学Java语言--第6周编程题_比巧克力巧的博客-程序员秘密

1单词长度(5分)题目内容:你的程序要读入一行文本,其中以空格分隔为若干个单词,以‘.’结束。你要输出这行文本中每个单词的长度。这里的单词与语言无关,可以包括各种符号,比如“it’s”算一个单词,长度为4。注意,行中可能出现连续的空格。输入格式:输入在一行中给出一行文本,以‘.’结束,结尾的句号不能计算在最后一个单词的长度内。输出格式:在一行中输出这行文本对应的单词的长度,每个长度之间以空格隔开,行末没有最后的空格。输入样例:It’s great to see you here.输出样例:

SFB 项目经验-45-用培训课件当运维文档,聪明_weixin_34391854的博客-程序员秘密

 以下是我与学生对话,仅想借此说明:(聪明的人,合理利用所有能利用的东西。) 以下是今天晚上给学生排错的感想:学生不按讲的做!跳着跳着做!我文档,1,2,3,4,5,6,7,8,9.....居然只做,3,4,来告诉我,我做不下去了做来报错!唉,学生,学生!越学越生!可想而知,课件不全的,学生怎么活,没法向下面走!所以,我一直认为讲课,课件也非常重要!当然老师更重要!没好的老师,做不出好的课件,...

sprd11.0系统添加应用锁功能_lockerlauncher_心有纤纤结的博客-程序员秘密

应用锁的效果如图:应用锁是限制应用启动**设计思路:1.后台将需要加需要加锁的apk包名通过接口传给设备端2.通过后台数据,更新桌面图标的状态(加锁活不加锁)3.应用锁图标是在原来apk的图标上覆盖一个锁的图片4.锁的图片是一个透明大图,里面的锁图放在右下方,5.锁的图片大小必须和apk图标大小一样,否则整体图标会模糊6.还加了 时间段限制; 在设置的时间段不允许启动;不在这个时间段允许启动修改的内容比较多,大概说下文件**frameworks/base/core/java/andro

非特定人语音识别,speaker-independent speech recognition,音标,读音,翻译,英文例句,英语词典..._编程大乐趣的博客-程序员秘密

补充资料:汉语语音识别分类汉语语音识别分类classification of Chinese speech recognition一种方法是用一个经过良好训练的非特定人或上述特定分类的标准样板或模型,发音人发少量自适应训练句,对已存人的标准样板或模型参数进行修改,使之适应该特定人。hQnyU yuyin shibie fenlei汉语语音识别分类(d理洛incatkm of Chin已记s碑搜h ...

随便推点

虚拟机CentOS7命令查看防火墙的状态以及开放端口_查看虚拟机防火墙状态_步步静心的博客-程序员秘密

命令:systemctl status firewalld.service 查看防火墙状态systemctl start firewalld.service 开启防护墙systemctl stop firewalld.service 关闭防火墙查看以及启动状态:关闭状态:查看已开放端口firewall-cmd --list-all防火墙开放端口:(开放端口后需重载防火墙)firewall-cmd --zone=public --add-port=80/tc

POJ 2284-That Nice Euler Circuit(计算几何_欧拉定理求平面被分成的区域数)_Rocky0429的博客-程序员秘密

That Nice Euler CircuitTime Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64uSubmit Status Practice POJ 2284Appoint description: System Crawler  (2015-05-16)

C# 笔记 MessageBox.Show_赵氏天儿的博客-程序员秘密

DialogResult click = MessageBox.Show("111", "tishi", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (click == DialogResult.Yes) { MessageBox.Show("点了YES"); } else { MessageBox.Show("点了...

分布式计算_A11691的博客-程序员秘密

分布式计算(英语:Distributed computing),又译为分散式运算。这个研究领域,主要研究分布式系统(Distributed system)如何进行计算。分布式系统是一组电脑,透过网络相互连接传递消息与通信后并协调它们的行为而形成的系统。[1]组件之间彼此进行交互以实现一个共同的目标。把需要进行大量计算的工程数据分割成小块,由多台计算机分别计算,再上传运算结果后,将结果统一合并得出数据结论的科学。分布式系统的例子来自有所不同的面向服务的架构,大型多人在线游戏,对等网络应用。目前分布式计算项目

C语言实验——拍皮球 SDUT_LqingX的博客-程序员秘密

C语言实验——拍皮球 SDUTTime Limit: 1000 ms Memory Limit: 65536 KiBSubmit StatisticProblem Description小瑜3岁了,很喜欢玩皮球,看来今后喜欢打篮球的_。最近她发现球从手中落下时,每次落地后反跳回原高度的一半,再落下,每次球落地时数球跳了几次,数到n次时爸爸在边上喊停,问小瑜现在球到底总共走了多少距离,小瑜故...

看动画轻松理解「递归」与「动态规划」_公众号:方志朋的博客-程序员秘密

点击上方“方志朋”,选择“置顶或者星标”你的关注意义重大!作者:程序员小吴来源:五分钟学算法在学习「数据结构和算法」的过程中,因为人习惯了平铺直叙的思维方式,所以「递归」与「动态规划」这种...

推荐文章

热门文章

相关标签