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. (部分答案来自网络)

     

     

  • 相关阅读:
    判断python字典中key是否存在的两种方法
    @SuppressWarnings("unused")注解的作用
    jsp常见的指令总结
    我们怎么获取数据库中的值或者在数据库中添加值那???
    sql语句中的问号是干什么的???
    第四天:servlet的生命周期和一些细节问题
    第三天:Servlet运行原理
    第二天:tomcat体系结构和第一个Servlet
    第一天:tomcat相关知识和浏览器的访问机制
    在用mvn编译java文件时遇到问题
  • 原文地址:https://www.cnblogs.com/qkhh/p/1807245.html
Copyright © 2011-2022 走看看