稀有TCP状态TCP状态机正常状态ClientServerclosedclosedclosedlisten(SYN)syn_sentsyn_received(SYN,ACK)established(ACK)establishedestablishedClientServerestablishedestablished(DATA)<======>(DATA)establishedestablishedClientServer(FIN)fin_wait1(ACK)fin_wait2close_wait(DATA)<------(DATA)(FIN)last_ack(ACK)time_waitclosedclosedclosedRef:TCP/IPStateTransitionDiagramRareState1CircumstanceOne-waycommunicationServer只从套接字读取,没有响应。客户端只向套接字写入数据,忽略响应。服务器将关闭连接后idleforXminsDemofunchandleRequest(connnet.Conn){buf:=make([]byte,1024)//deferconn.(*net.TCPConn).CloseWrite()//ShutDown(SHUT_WR)//deferconn.(*net.TCPConn).CloseRead()//ShutDown(SHUT_RD)deferconn.Close()for{conn.SetReadDeadline(time.Now().Add(10*time.Second))reqLen,err:=conn.Read(buf)iferr!=nil{DoLog("E读取错误[%v]",err.Error())return}else{DoLog("INFOread[%v]Message[%v]",reqLen,string(buf))}//conn.Write([]byte("Messagereceived."))}}ResultWegotadatalosshere.RareState1CLOSE_WAITEdoconn.Write()witha[]byte->它运行正常没有错误!它需要另一个conn.Write才能得到错误:brokenpipe[DataLoss]()whatweexpected:[fin_wait2(Server)|close_wait(Client)]()|(DATA)<------------|----------(DATA)为什么只有一个数据丢失?21:13:03.505439IP127.0.0.1.5555>127.0.0.1.6882:Flags[F.],seq1,ack4,win256,options[nop,nop,TSval1996918705ecr1996913703],长度021:13:03.506316IP127.0.0.1.6882>127.0.0.1.5555:标志[.],ack2,win257,选项[nop,nop,TSval1996918706ecr1996918705],长度021:13:06.783940IP127.0.0.1.6882>127.0.0.1.5555:Flags[P.],seq4:5,ack2,win257,options[nop,nop,TSval1996921983ecr1996918705],长度121:13:06.783975IP127.0.0.1.5555>127.0.0.1.6882:Flags[R],seq4031687754,win0,length0关闭与关闭关闭网络连接的正常方法是调用关闭函数。但是,关闭有两个限制可以通过关闭来避免:Close()终止数据传输的两个方向,读取和写入。由于TCP连接是全双工的,有时我们想告诉另一端我们已完成发送,即使那端可能有更多数据要发送给我们。Close()仅在fd引用为0时终止套接字close()递减描述符的引用计数并仅在计数达到0时关闭套接字。shutdown()中断共享socketid的所有进程的连接。读的会检测到EOF,写的会重新接收SIGPIPE,REFshutdownFunctionNOTE:ashutdownwillnotcloseasocket.重要的是要注意shutdown()不动作最终关闭文件描述符——它只是改变了它的可用性。要释放套接字描述符,您需要使用close()。shutdown、close和lingerTheeffectofansetsockopt(...,SO_LINGER,...)取决于linger结构中的值(传递给setsockopt的第三个参数())是:Case1:linger->l_onoffiszero(linger->l_lingerhasnomeaning):这是默认的.在面向连接的协议(如TCP)的情况下,堆栈还确保发送的数据得到对等方的确认。堆栈将在后台执行上述优雅关闭(在调用close()返回后),无论套接字是阻塞还是非阻塞。情况2:linger->l_onoff非零且linger->l_linger为零:Aclose()立即返回。底层堆栈丢弃任何未发送的数据,并且,在面向连接的协议(如TCP)的情况下,向对等方发送RST(重置)(这称为硬关闭或异常关闭)。对等应用程序对read()/recv()数据的所有后续尝试都将导致ECONNRESET。案例3:linger->l_onoff非零且linger->l_linger非零:close()将阻塞(如果是阻塞套接字)或EWOULDBLOCK失败(如果是非阻塞)直到正常关闭完成或linger->l_linger中指定的时间过去(超时)。超时后,堆栈的行为与上述情况2相同。如何获得单向通信:CloseWrite(关闭)而不是Close()DemoREFREFBeej网络编程指南REFclosevsshutdownsocket?REFTheultimateSO_LINGERpage,or:whyismytcpnotreliableGo语言TCPSocket编程socket链接的关闭和关闭的区别_TIME_WAIT和CLOSE_WAIT什么时候出现_如何处理锁socket:close()和hutdown()的差异HowtopreventthedatalossCheckConnectionClosedbeforewrite.SocketReadingolangisblock(GoRuntimeunderlyingsocketisNon-blocksocket+epool)GoschedulerfuncCheckFdCloseWait(conn*net.TCPConn)(flagbool){fileDesc,errFile:=conn.File()ifnil!=errFile{returnfalse}msg:=make([]byte,0)nRead,_,err:=syscall.Recvfrom(int(fileDesc.Fd()),msg,syscall.MSG_DONTWAIT)DoLog("CheckFdCloseWaitnRead[%v]err[%v]",nRead,err)ifnil==err&&nRead==0{returntrue}返回false}DEMO
