搜到这个了,但是没太看懂。。三. read/write对连接异常的反馈行为:对应用程序来说,与另一进程的TCP通信其实是完全异步的过程:我并不知道对面什么时候、能否收到我的数据我不知道什么时候能够收到对面的数据我不知道什么时候通信结束(主动退出或是异常退出、机器故障、网络故障等等)对于1和2,采用write() -> read() -> write() -> read() ->…的序列,通过blocking read或者nonblock read+轮询的方式,应用程序基于可以保证正确的处理流程。对于3,kernel将这些事件的“通知”通过read/write的结果返回给应用层。假设A机器上的一个进程a正在和B机器上的进程b通信:某一时刻a正阻塞在socket的read调用上(或者在nonblock下轮询socket)当b进程终止时,无论应用程序是否显式关闭了socket(OS会负责在进程结束时关闭所有的文件描述符,对于socket,则会发送一个FIN包到对面)。同步通知:进程a对已经收到FIN的socket调用read,如果已经读完了receive buffer的剩余字节,则会返回EOF:0异步通知:如果进程a正阻塞在read调用上(前面已经提到,此时receive buffer一定为空,因为read在receive buffer有内容时就会返回),则read调用立即返回EOF,进程a被唤醒。socket在收到FIN后,虽然调用read会返回EOF,但进程a依然可以其调用write,因为根据TCP协议,收到对方的FIN包只意味着对方不会再发送任何消息。 在一个双方正常关闭的流程中,收到FIN包的一端将剩余数据发送给对面(通过一次或多次write),然后关闭socket。但是事情远远没有想象中简单。优雅地(gracefully)关闭一个TCP连接,不仅仅需要双方的应用程序遵守约定,中间还不能出任何差错。假如b进程是异常终止的,发送FIN包是OS代劳的,b进程已经不复存在,当机器再次收到该socket的消息时,会回应RST(因为拥有该socket的进程已经终止)。a进程对收到RST的socket调用write时,操作系统会给a进程发送SIGPIPE,默认处理动作是终止进程,知道你的进程为什么毫无征兆地死亡了吧:)

解决方案 »

  1. 想到一个办法,在客户端加一个serversocket去监听,因为当客户端连上服务器的时候,服务器是有 客户端IP记录的,如果服务器检查到自身的外网IP变了,就创建clientsocket连到客户端的serversocket去,客户端的serversocket收到这个连接就知道服务器的新ip,然后就可以再连服务器,服务器替换掉socket。当然还要改应用层协议,重连时要发一个特殊的数据,服务器要能正确解析是重连,查找之前的连接替换
    当然这方法有个不足的地方,就是如果客户端没有外网IP就会失败,本来正常情况下客户端不需要外网IP的
      

类似问题 »