zoukankan      html  css  js  c++  java
  • 关于Socket的一些细节

    前记

      最近几天在排除一个软件的BUG,一段看似简单且没有问题的代码却带来了灾难性的错误。由此想到总结一下关于socket操作的一些细节。要知道,事情总是败在细节上,尽管这段代码只有两行,经过修改后也不超过10行,但是让两个人忙活了至少两天的时间,这还不包括后续的重新发布管理的所消耗的人力和时间。下面论述的一些代码是针对C#语言的。

     

    问题总结

    1. TCP连接中,最后释放连接要经过四次握手,每次握手后,不论都客户端还是服务都会处于一个特定的状态,这几个状态是什么?

    答案:看以下的交互图:

             Client                  消息                   Server

             close()

                                ------ FIN ------->

            FIN_WAIT1                                 CLOSE_WAIT

                                <----- ACK -------

            FIN_WAIT2 

                                                         close()

                                <------ FIN ------  

            TIME_WAIT                               LAST_ACK      

                               ------ ACK ------->  

                                                        CLOSED

             CLOSED

    可知,客户端会依次处于FIN_WAIT1, FIN-WAIT2, TIME_WAIT, CLOSED四个状态;服务器端会依次处于CLOSE_WAIT, LAST_ACK, CLOSED三个状态。

     

    2. 使用socket进行阻塞的接收操作,是调用Receive函数来实现。如果一方在等待接收,而另一方主动关闭了连接,阻塞会立即停止,那么会发生以下几种操作中哪一种呢?

    返回0

    返回负数

    抛出异常

    正在等待接收,表示连接是正常的。另一方主动关闭连接后,接收方会返回0.注意在阻塞的交互模式下,Receive函数不会因为接收时的网络问题而抛出异常。

     

    3. Receive这个函数,又有返回值,又会抛出异常。而返回值又不单单表示接收的数量,还会表示其它的意思,设计者为什么要这么做呢?为什么不统一到抛出异常或通过返回值来表达正确还是错误呢?

    抛出异常只是对参数进行验证时,或调用其它函数时抛出的异常,对于接收的错误,只是返回0或负数。返回0表示socket已关闭,返回负数表示操作失败。

     

    4. 发送方通过阻塞方式地发送数据,调用的是Send函数,当在发送数据的时候,接收方关闭了连接,或者网络中断了?Send函数会发生哪种行为?

    返回0

    返回负数

    返回已经发送的数据的长度

    抛出异常

    还是返回0

     

    5. Poll函数是干什么用的?在操作过程中必需用吗?如果用,有什么好处,如果不用有什么坏处?

    其行为非常像Mutex,用来等待socket某个状态的有效。比如说,如果正在操作的socket的状态是读取,而现在又要写入,则需要等读取完了之后再写入,用Poll可以使当着线程阻塞一直等到socket可写。同样,如果要读的时候也是这样。用Poll得保证了安全地读和写。

     

    6. 同样是关闭,却有ShutdownClose两个函数,它们有什么区别呢?在实际应用中,应该怎么正确地使用它?

    Shutdown关闭网络,它带有三个参数:只关闭读通道、只关闭写通道、关闭读写通道。通过Reflector反编译查看,可以看到,在Close中调用了Dispose函数,而在Dispose函数中主要做了两件事,关闭发送通道(写通道)和销毁socketHandle

    在实际使用中,如果单独使用Shutdown来关闭发送通道,则无法销毁Handle,如果只使用Close来关闭,则又没有关闭网络的接收通道,可能造成数据丢失。因此,最好的是使用Shutdown来关闭网络通道,再用Close来做完全的清理工作。

     

    7. 有些服务器程序,在运行一段时间后,就出现了大量的CLOSE_WAIT连接(用netstat -na可以看到),分析为什么会出现这样的情况?

    CLOSE_WAIT一般是由于一端调用了Close而另外一端没有调用Close造成的。当主动关闭的一方发送FIN到被动关闭这边后,被动关闭这边的TCP马上回应一个ACK过去,同时向上面应用程序提交一个ERROR,导致上面的SOCKETsend或者recv返回SOCKET_ERROR,正常情况下,如果上面在返回SOCKET_ERROR后调用了 closesocket,那么被动关闭的者一方的TCP就会发送一个FIN过去,自己的状态就变迁到LAST_ACK. (部分答案来自网络)

     

     

  • 相关阅读:
    [转]一致性hash算法
    [转]算法的时间复杂度和空间复杂度详解
    [转]B树(多向平衡查找树)详解
    spring中ApplicationContextAware接口描述
    [转]web.xml中<url-pattern>详解
    [转]linux中vim命令
    [转]Java GC的原理
    [转]浅谈UML的概念和模型之UML九种图
    Jmeter做读取csv接口测试
    IDLE崩溃:IDLE's subprocess didn't make connection. Either IDLE can't start a...
  • 原文地址:https://www.cnblogs.com/qkhh/p/1807245.html
Copyright © 2011-2022 走看看