TCP的连接状态标识(SYN,FIN,ACK,PSH,RST,URG)
TCP层,有个FLAGS字段,这个字段有以下⼏个标识:SYN, FIN, ACK, PSH, RST, URG.
其中,对于我们⽇常的分析有⽤的就是前⾯的五个字段。它们的含义是:
(1)SYN表⽰建⽴连接,
(2)FIN表⽰关闭连接,
(3)ACK表⽰响应,
(4)PSH表⽰有 DATA数据传输,
(5)RST表⽰连接重置。
其中,ACK是可能与SYN,FIN等同时使⽤的,⽐如SYN和ACK可能同时为1,它表⽰的就是建⽴连接之后的响应,
如果只是单个的⼀个SYN,它表⽰的只是建⽴连接。
TCP的⼏次握⼿就是通过这样的ACK表现出来的。
但SYN与FIN是不会同时为1的,因为前者表⽰的是建⽴连接,⽽后者表⽰的是断开连接。
RST⼀般是在FIN之后才会出现为1的情况,表⽰的是连接重置。
⼀般地,当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接;⽽当出现SYN和SYN+ACK包时,我们认为客户端与服务器建⽴了⼀个连接。
PSH为1的情况,⼀般只出现在 DATA内容不为0的包中,也就是说PSH为1表⽰的是有真正的TCP数据包内容被传递。
TCP的连接建⽴和连接关闭,都是通过请求-响应的模式完成的。
概念补充-TCP三次握⼿:
TCP(Transmission Control Protocol)传输控制协议
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采⽤三次握⼿确认建⽴⼀个连接:
位码即tcp标志位,有6种标⽰:SYN(synchronous建⽴联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束)
RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码)
第⼀次握⼿:主机A发送位码为syn=1,随机产⽣seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建⽴联机;第⼆次握⼿:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产⽣seq=7654321的包;
第三次握⼿:主机A收到后检查ack number是否正确,即第⼀次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建⽴成功。
完成三次握⼿,主机A与主机B开始传送数据。
在TCP/IP协议中,TCP协议提供可靠的连接服务,采⽤三次握⼿建⽴⼀个连接。网络连接被重设
第⼀次握⼿:建⽴连接时,客户端发送syn包(syn=j)到服务器,并进⼊SYN_SEND状态,等待服务器确认;
第⼆次握⼿:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时⾃⼰也发送⼀个SYN包(syn=k),即SYN+ACK包,此时服务器进⼊SYN_RECV状态;
第三次握⼿:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进⼊ESTABLISHED状态,完成三次握⼿。完成三次握⼿,客户端与服务器开始传送数据。
【注意】中断连接端可以是Client端,也可以是Server端。
假设Client端发起中断连接请求,也就是发送FIN报⽂。Server端接到FIN报⽂后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候Client端就进⼊FIN_WAIT状态,继续等待Server端的FIN报⽂。当Server端确定数据已发送完成,则向Client端发送FIN报⽂,"告诉Client端,好了,我这边数据发完了,准备好关闭连接了"。Client端收到FIN报⽂后,"就知道可以关闭连接了,但是他还是不相信⽹络,怕Server端不知道
要关闭,所以发送ACK后进⼊TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,"就知道可以断开连接了"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!
整个过程Client端所经历的状态如下:
⽽Server端所经历的过程如下:
【注意】 在TIME_WAIT状态中,如果TCP client端最后⼀次发送的ACK丢失了,它将重新发送。TIME_WAIT状态中所需要的时间是依赖于实现⽅法的。典型的值为30秒、1分钟和2分钟。等待之后连接正式关闭,并且所有的资源(包括端⼝号)都被释放。
【问题1】为什么连接的时候是三次握⼿,关闭的时候却是四次握⼿?
答:因为当Server端收到Client端的SYN连接请求报⽂后,可以直接发送SYN+ACK报⽂。其中ACK报⽂是⽤来应答的,SYN报⽂是⽤来同步的。但是关闭连接时,当Server端收到FIN报⽂时,很可能并不会⽴即关闭SOCKET,所以只能先回复⼀个ACK报⽂,告诉Client 端,"你发的FIN报⽂我收到了"。只有等到我Server端所有的报⽂都发送完了,我才能发送FIN报⽂,因此不能⼀起发送。故需要四步握⼿。
【问题2】为什么TIME_WAIT状态需要经过2MSL(最⼤报⽂段⽣存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报⽂都发送完毕,我们可以直接进⼊CLOSE状态了,但是我们必须假象⽹络是不可靠的,有可以最后⼀个ACK丢失。所以TIME_WAIT状态就是⽤来重发可能丢失的ACK报⽂。
10054错位码
有⼈问:select写socket时候 建⽴链接⽴马发送数据有时候收不到数据 还提⽰10054 ,⼤多数的况还是能收到的 ⼀般收不到数据的时候第⼆次再链接发送数据就能收到 请问是怎么回事呢?
对于好奇⼼极强的我,对于这个没遇到的问题,我就百度了10054错误。⽹上说:
⼀般来说是连接被对⽅重设。⼀个建⽴的连接被远程主机强⾏关闭,若远程主机上的进程异常终⽌运⾏(由于内存冲突或硬件故障),或者针对套接字执⾏了⼀次强⾏关闭,便会产⽣10054错误。针对强⾏关闭的情况,可⽤SO_LINGER套接字选项和setsockopt来配置⼀个套接字。
⽽对于 ⾥描述的那个问题,我回忆了 TCP/IP 协议,我认为会有如下两种情况:
(1)client 在与 server 进⾏三次握⼿时,client 调⽤ connect 函数完成了连接的建⽴(客户端⾃以为建⽴了),⽽实际server 那边却没有收到最后⼀次握⼿ ack 的回复。这时触发了 server 的 syn 触发器,重发 SYN+ACK 包,⼀般默认是重发 5次,时间分别是 1秒、2秒、4秒、8秒、16秒;⽽此时client 马上发送数据的话,server 会发 RST 回复给 client, 那么此时 client 就会提⽰ 10054。
(2)⽽另⼀种情况就是 server 这边的 accept 队列满了(⼀般有 syn_recv 队列,accept队列),那么此时 server会直接回复RST(最新的 linux 内核是这么实现的),当然也有可能会拒绝 client的请求,
让 client⾃⼰⾃动断开请求。
⾥的⼀位⼤神(冒泡)说实现第⼆种⽅式,也就是拒绝 client发过来的请求,原因如下:
第⼀,服务器已经处理不过来了,再发rst加剧压⼒
第⼆,客户端如果丢包,会等到超时再重试,⽽收到rst的话有可能⽴刻重试,服务器压⼒会更⼤。
Linux⽹络编程中socket常见错误码分析
EINTR: 4
阻塞的操作被取消阻塞的调⽤打断。如设置了发送接收超时,就会遇到这种错误。
只能针对阻塞模式的socket。读,写阻塞的socket时,-1返回,错误号为INTR。另外,如果出现EINTR即errno为4,错误描述
Interrupted system call,操作也应该继续。如果recv的返回值为0,那表明连接已经断开,接收操作也应该结束。
ETIMEOUT:110
1、操作超时。⼀般设置了发送接收超时,遇到⽹络繁忙的情况,就会遇到这种错误。
2、服务器做了读数据做了超时限制,读时发⽣了超时。
3、错误被描述为“connect time out”,即“连接超时”,这种情况⼀般发⽣在服务器主机崩溃。此时客户 TCP 将在⼀定时间内(依具体实现)持续重发数据分节,试图从服务 TCP 获得⼀个 ACK 分节。当最终放弃尝试后(此时服务器未重新启动),内核将会向客户进程返回 ETIMEDOUT 错误。如果某个中间路由器判定该服务器主机已经不可达,则⼀般会响应“destination unreachable”-“⽬的地不可达”的ICMP消息,相应的客户进程返回的错误是 EHOSTUNREACH 或ENETUNREACH。当服务器重新启动后,由于 TCP 状态丢失,之前所有的连接信息也不存在了,此时对于客户端发来请求将回应 RST。如果客户进程对检测服务器主机是否崩溃很有必要,要求即使客户进程不主动发送数据也能检测出来,那么需要使⽤其它技术,如配置 SO_KEEPALIVE Socket 选项,或实现某些⼼跳函数。
EAGAIN:
1、Send返回值⼩于要发送的数据数⽬,会返回EAGAIN和EINTR。
2、recv 返回值⼩于请求的长度时说明缓冲区已经没有可读数据,但再读不⼀定会触发EAGAIN,有可能返回0表⽰TCP连接已被关闭。
3、当socket是⾮阻塞时,如返回此错误,表⽰写缓冲队列已满,可以做延时后再重试.
4、在Linux进⾏⾮阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),表明在⾮阻塞模式下调⽤了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不⽤管它,下次循环接着recv就可以。对⾮阻塞socket⽽⾔,EAGAIN不是⼀种错误。
EPIPE:
1、Socket 关闭,但是socket号并没有置-1。继续在此socket上进⾏send和recv,就会返回这种错误。这个错误会引发SIGPIPE信号,系统会将产⽣此EPIPE错误的进程杀死。所以,⼀般在⽹络程序中,⾸先屏蔽此消息,以免发⽣不及时设置socket进程被杀死的情况。
2、write(..) on a socket that has been closed at the other end will cause a SIGPIPE.
3、错误被描述为“broken pipe”,即“管道破裂”,这种情况⼀般发⽣在客户进程不理会(或未及时处理)Socket 错误,继续向服务TCP 写⼊更多数据时,内核将向客户进程发送 SIGPIPE 信号,该信号默认会使进程终⽌(此时该前台进程未进⾏ core dump)。结合上边的 ECONNRESET 错误可知,向⼀个 FIN_WAIT2 状态的服务 TCP(已 ACK 响应 FIN 分节)写⼊数据不成问题,但是写⼀个已接收了RST 的 Socket 则是⼀个错误。
EBADF:
read(..) or write(..) on a locally closed socket will return EBADF
EFAULT:
地址错误。
EBUSY:
ECONNREFUSED:
1、拒绝连接。⼀般发⽣在连接建⽴时。
拔服务器端⽹线测试,客户端设置keep alive时,recv较快返回0, 先收到ECONNREFUSED (Connection refused)错误码,其后都是ETIMEOUT。
2、an error returned from connect(), so it can only occur in a client (if a client is defined as the party that initiates the connection
ECONNRESET:
1、在客户端服务器程序中,客户端异常退出,并没有回收关闭相关的资源,服务器端会先收到ECONNRESET错误,然后收到EPIPE错误。
2、连接被远程主机关闭。有以下⼏种原因:远程主机停⽌服务,重新启动;当在执⾏某些操作时遇到失败,因为设置了“keep alive”选项,连接被关闭,⼀般与ENETRESET⼀起出现。
3、远程端执⾏了⼀个“hard”或者“abortive”的关闭。应⽤程序应该关闭socket,因为它不再可⽤。当执⾏在⼀个UDP socket上时,这个错误表明前⼀个send操作返回⼀个ICMP“port unreachable”信息。
4、如果client关闭连接,server端的select并不出错(不返回-1,使⽤select对唯⼀⼀个socket进⾏non- blocking检测),但是写该socket就会出错,⽤的是send.错误号:ECONNRESET.读(recv)socket并没有返回错误。
5、该错误被描述为“connection reset by peer”,即“对⽅复位连接”,这种情况⼀般发⽣在服务进程较客户进程提前终⽌。当服务进程终⽌时会向客户 TCP 发送 FIN 分节,客户 TCP 回应 ACK,服务 TCP 将转⼊ FIN_WAIT2 状态。此时如果客户进程没有处理该 FIN (如阻塞在其它调⽤上⽽没有关闭 Socket 时),则客户 TCP 将处于 CLOSE_WAIT 状态。当客户进程再次向 FIN_WAIT2 状态的服务TCP 发送数据时,则服务 TCP 将⽴刻响应 RST。⼀般来说,这种情况还可以会引发另外的应⽤程序异常,客户进程在发送完数据后,往往会等待从⽹络IO接收数据,很典型的如 read 或 readline 调⽤,
此时由于执⾏时序的原因,如果该调⽤发⽣在 RST 分节收到前执⾏的话,那么结果是客户进程会得到⼀个⾮预期的 EOF 错误。此时⼀般会输出“server terminated prematurely”-“服务器过早终⽌”错误。
EINVAL:
⽆效参数。提供的参数⾮法。有时也会与socket的当前状态相关,如⼀个socket并没有进⼊listening状态,此时调⽤accept,就会产⽣EINVAL错误。
EMFILE:
打开了太多的socket。对进程或者线程⽽⾔,每种实现⽅法都有⼀个最⼤的可⽤socket数⽬处理,或者是全局的,或者是局部的。
EWOULDBLOCK:EAGAIN
资源暂时不可⽤。这个错误是从对⾮阻塞socket进⾏的不能⽴即结束的操作返回的,如当没有数据在队列中可以读时,调⽤recv。并不是fatal错误,稍后操作可以被重复。调⽤在⼀个⾮阻塞的SOCK_STREAM socket 上调⽤connect时会产⽣这个错误,因为有时连接建⽴必须消耗⼀定的时间。
ENOTCONN
在⼀个没有建⽴连接的socket上,进⾏read,write操作会返回这个错误。出错的原因是socket没有标识地址。Setsoc也可能会出错。
ECONNRESET
Connection reset by peer.
连接被远程主机关闭。有以下⼏种原因:远程主机停⽌服务,重新启动;当在执⾏某些操作时遇到失败,因为设置了“keep alive”选项,连接被关闭,⼀般与ENETRESET⼀起出现。
ECONNABORTED
1、软件导致的连接取消。⼀个已经建⽴的连接被host⽅的软件取消,原因可能是数据传输超时或者是协议错误。
2、该错误被描述为“software caused connection abort”,即“软件引起的连接中⽌”。原因在于当服务和客户进程在完成⽤于 TCP 连接的“三次握⼿”后,客户 TCP 却发送了⼀个 RST (复位)分节,在服务进程看来,就在该连接已由 TCP 排队,等着服务进程调⽤accept 的时候 RST 却到达了。POSIX 规定此时的 errno 值必须 ECONNABORTED。源⾃ Berkeley 的实现完全在内核中处理中⽌的连接,服务进程将永远不知道该中⽌的发⽣。服务器进程⼀般可以忽略该错误,直接再次调⽤accept。
当TCP协议接收到RST数据段,表⽰连接出现了某种错误,函数read将以错误返回,错误类型为ECONNERESET。并且以后所有在这个套接字上的读操作均返回错误。错误返回时返回值⼩于0。
ENETUNREACH
⽹络不可达。Socket试图操作⼀个不可达的⽹络。这意味着local的软件知道没有路由到达远程的host。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论