Python中Socket的Close方法假关闭Socket连接的问题

来源:互联网 发布:淘宝棒球服外套女 编辑:程序博客网 时间:2024/05/23 14:45

最近用python的Socket写了一个传输通讯测试工具,但是发现在Server端调用close方法后,如果循环没有break的话,此连接还可以继续用来发送和接收数据。所以,我就觉得很是奇怪,难道close方法关闭的连接没有起作用吗?经过试验后,确实如此,以下是我的事例代码,

Server端代码:          

from socket import *import threading,os,timeclass Server():    def __init__(self,host='127.0.0.1',port=9990):        try:             addr=(host,port)            self.tcpSerSock=socket(AF_INET,SOCK_STREAM)            self.tcpSerSock.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)            self.tcpSerSock.bind(addr)            self.tcpSerSock.listen(5)        except Exception,e :            print 'ip or port error :',str(e)            self.tcpSerSock.close()                def main(self):        while 1 :            try :                print 'wait for connecting ...'                tcpCliSock,addr = self.tcpSerSock.accept()                addrStr = addr[0]+':'+str(addr[1])                print 'connect from',addrStr            except KeyboardInterrupt:                self.close=True                tcpCliSock.close()                self.tcpSerSock.close()                print 'KeyboardInterrupt'                break            ct = ClientThread(tcpCliSock,addrStr)             ct.start()            class ClientThread(threading.Thread):    def __init__(self,tcpClient,addr):        super(ClientThread,self).__init__()                self.tcpClient = tcpClient        self.addr = addr        self.timeout = 60        tcpClient.settimeout(self.timeout)        self.cf = tcpClient.makefile('rw',0)            def run(self):        while 1:            try:                data = self.cf.readline().strip()                if data:                    if data.find("set time")>=0:                        self.timeout = int(data.replace("set time ",""))                        self.tcpClient.settimeout(self.timeout)                    print self.addr,"client say:",data                    self.cf.write(str(self.addr)+" recevied ok!"+"\n")                else:                    break            except Exception,e:                self.tcpClient.close()                self.cf.write("time out !"+"\n")                print self.addr,"send message error,",str(e)#此处将break注释掉#                breakif __name__ == "__main__" :    ser = Server()    ser.main()


Client端代码:

from socket import *class Client():    def __init__(self):        pass        def main(self):        tcpCliSock=socket(AF_INET,SOCK_STREAM)        tcpCliSock.connect(('127.0.0.1',9990))        print 'connect server 9999 successfully !'        cf = tcpCliSock.makefile('rw', 0)        while 1:            data=raw_input('>')            try:                if data:                    cf.write(data+"\n")                    data = cf.readline().strip()                    if data:                        print "server say:",data                    else:                        break                else:                    break            except Exception,e:                print "send error,",str(e)if __name__ == "__main__":    cl = Client()    cl.main()



在代码中可以看出,如果timeout后,except肯定能够捕获到timeout异常,这样就会进入到except代码中,在上面我们故意将break注释掉,也就是不让其跳出循环,经过试验,可以得知,虽然在server端已经将连接close掉了,但是client端仍然可以顺利的接收到消息,而且,如果client端发送数据的间隔小于超时时间的话,此连接可以顺利的一直使用,这样,我们close貌似就一点儿效果都没有了,经过在百度搜索,一直米有找到解决办法,最后还是硬着头皮去看鸟语文档,下面是官方解释:

close()releases the resource associated with a connection but does not necessarily close the connection immediately. If you want to close the connection in a timely fashion, callshutdown() beforeclose().

大体意思是:close方法可以释放一个连接的资源,但是不是立即释放,如果想立即释放,那么请在close之前使用shutdown方法,可是shutdown方法是干什么的呢?

还得继续看鸟语,官方解释如下:

Shut down one or both halves of the connection. If how is SHUT_RD, further receives are disallowed. If how isSHUT_WR, further sends are disallowed. Ifhow isSHUT_RDWR, further sends and receives are disallowed. Depending on the platform, shutting down one half of the connection can also close the opposite half (e.g. on Mac OS X,shutdown(SHUT_WR) does not allow further reads on the other end of the connection).

大体意思是:shutdown方法是用来实现通信模式的,模式分三种,SHUT_RD 关闭接收消息通道,SHUT_WR 关闭发送消息通道,SHUT_RDWR 两个通道都关闭

也就是说,想要关闭一个连接,首先把通道全部关闭,然后在release连接,以上三个静态变量分别对应数字常量:0,1,2

所以,要实现我们的功能,只需要改变server端的代码,也就是

    except Exception,e:                self.tcpClient.close()                self.cf.write("time out !"+"\n")                print self.addr,"send message error,",str(e)#此处将break注释掉#                break


改为:

    except Exception,e:self.tcpClient.shutdown(2)                self.tcpClient.close()                self.cf.write("time out !"+"\n")                print self.addr,"send message error,",str(e)                break

这样的话,在close后,再调用 self.cf.write("time out !"+"\n"),应该就会报异常,此时client再使用此连接向server发数据,就会出错,然后就会顺理成章的走except的代码了。

当然,上面的代码,self.cf.write("time out !"+"\n")代码可以注释掉,我只是想用它来测试是否会出异常而已。




0 0
原创粉丝点击