【发布时间】:2014-07-21 21:13:58
【问题描述】:
我正在使用 socket 模块在 python 中创建一个服务器/客户端应用程序,无论出于何种原因,我的服务器一直在结束连接。奇怪的是,这在 Windows 上完美运行,但在 Linux 上却不行。我到处寻找可能的解决方案,但都没有奏效。下面是利用漏洞的代码的净化版本,但是成功率更高。通常它永远不会起作用。希望这仍然是足够的信息。谢谢!
服务器:
import logging
import socket
import threading
import time
def getData():
HOST = "localhost"
PORT = 5454
while True:
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) #because linux doesn't like reusing addresses by default
s.bind( ( HOST, PORT ) )
logging.debug( "Server listens" )
s.listen( 5 )
conn, addr = s.accept()
logging.debug( "Client connects" )
print "Connected by,", addr
dataRequest = conn.recv( 1024 )
logging.debug( "Server received message" )
time.sleep( .01 ) #usually won't have to sample this fast
data = """Here is some data that is approximately the length
of the data that I am sending in my real server. It is a string that
doesn't contain any unordinary characters except for maybe a tab."""
if not timeThread.isAlive(): #lets client know test is over
data = "\t".join( [ data, "Terminate" ] )
conn.send( data )
s.close()
print "Finished"
print "Press Ctrl-C to quit"
break
else:
logging.debug( "Server sends data back to client" )
conn.send( data )
logging.debug( "Server closes socket" )
s.close()
def timer( t ):
start = time.time()
while ( time.time() - start ) < t:
time.sleep( .4 )
#sets flag for another thread not here
def main():
global timeThread
logging.basicConfig( filename="test.log", level=logging.DEBUG )
#time script runs for
t = 10 #usually much longer (hours)
timeThread = threading.Thread( target=timer, args=( t, ) )
dataThread = threading.Thread( target=getData, args=() )
timeThread.start()
dataThread.start()
#just for testing so I can quit threads when sockets break
while True:
time.sleep( .1 )
timeThread.join()
dataThread.join()
if __name__ == "__main__":
main()
客户:
import logging
import socket
def getData():
dataList = []
termStr = "Terminate"
data = sendDataRequest()
while termStr not in data:
dataList.append( data )
data = sendDataRequest()
dataList.append( data[ :-len( termStr )-1 ] )
def sendDataRequest():
HOST = "localhost"
PORT = 5454
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
while True:
try:
s.connect( ( HOST, PORT ) )
break
except socket.error:
print "Connecting to server..."
logging.debug( "Client sending message" )
s.send( "Hey buddy, I need some data" ) #approximate length
try:
logging.debug( "Client starts reading from socket" )
data = s.recv( 1024 )
logging.debug( "Client done reading" )
except socket.error, e:
logging.debug( "Client throws error: %s", e )
print data
logging.debug( "Client closes socket" )
s.close()
return data
def main():
logging.basicConfig( filename="test.log", level=logging.DEBUG )
getData()
if __name__ == "__main__":
main()
编辑:添加回溯
Traceback (most recent call last):
File "client.py", line 39, in <moduel>
main()
File "client.py", line 36, in main
getData()
File "client.py", line 10, in getData
data = sendDataRequest()
File "client.py", line 28, in sendDataRequest
data = s.recv( 1024 )
socket.error: [Errno 104] Connection reset by peer
编辑:添加调试
DEBUG:root:Server listens
DEBUG:root:Client sending message
DEBUG:root:Client connects
DEBUG:root:Client starts reading from socket
DEBUG:root:Server received message
DEBUG:root:Server sends data back to client
DEBUG:root:Server closes socket
DEBUG:root:Client done reading
DEBUG:root:Server listens
DEBUG:root:Client sending message
DEBUG:root:Client connects
DEBUG:root:Client starts reading from socket
DEBUG:root:Server received message
DEBUG:root:Server sends data back to client
DEBUG:root:Client done reading
DEBUG:root:Client sending message
DEBUG:root:Client starts reading from socket
DEBUG:root:Server closes socket
DEBUG:root:Client throws error: [Errno 104] Connection reset by peer
DEBUG:root:Server listens
汤姆的理论似乎是正确的。我会尝试弄清楚如何更好地关闭连接。
这没有解决,但接受的答案似乎指出了问题。
编辑:我尝试使用 Tom 的 getData() 函数,但看起来服务器仍然过早关闭连接。应该是可重复的,因为我也无法让它在 Windows 中工作。
服务器输出/回溯:
Connected by, ('127.0.0.1', 51953)
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib64/python2.6/threading.py", line 532, in __bootstrap_inner
self.run()
File "/usr/lib64/python2.6/threading.py", line 484, in run
self.__target(*self.__args, **self.__kwargs)
File "server.py", line 15, in getData
s.bind( ( HOST, PORT ) )
File "<string>", line 1, in bind
error: [Errno 22] Invalid argument
客户端输出/回溯:
Here is some data that is approximately the length
of the data that I am sending in my real server. It is a string that
doesn't contain any unordinary characters except for maybe a tab.
Traceback (most recent call last):
File "client.py", line 49, in <moduel>
main()
File "client.py", line 46, in main
getData()
File "client.py", line 11, in getData
data = sendDataRequest()
File "client.py", line 37, in sendDataRequest
print data
UnboundLocalError: local variable 'data' referenced before assignment
日志:
DEBUG:root:Server listens
DEBUG:root:Client sending message
DEBUG:root:Client connects
DEBUG:root:Client starts reading from socket
DEBUG:root:Server received message
DEBUG:root:Server sends data back to client
DEBUG:root:Server closes connection
DEBUG:root:Client done reading
DEBUG:root:Client closes socket
DEBUG:root:Client sending message
DEBUG:root:Client starts reading from socket
DEBUG:root:Client throws error: [Errno 104] Connection reset by peer
更新:我使用了 Tom 的 getData() 函数,但将 s.bind() 移动到循环之前并让它工作。老实说,我不知道为什么会这样,所以如果有人能解释为什么服务器关闭它的客户端套接字是安全的,但当它关闭它的服务器套接字时却不是这样,那就太酷了。谢谢!
【问题讨论】:
-
您是否 100000% 肯定这不是实际的连接问题? tcpdump/wireshark 说什么?你能用
nc测试连接吗? -
您能否提供更具体的信息,说明在您遇到错误之前服务器和客户端都走了多远 - 以及客户端和服务器的确切错误/堆栈跟踪是什么?
-
@admdrew 我不明白这可能是与 localhost 的连接问题,但我可以在几分钟内得到它
-
@TomDalton 当然,我会在几分钟后发布。至于多远,一般是5秒。有时它会完成(10 秒),但不会连续多次。
-
您服务器的
while True循环似乎一直在打开一个新套接字,而客户端没有任何信号表明套接字已完成或客户端已完成读取数据 - 这是故意的吗?
标签: python