使用 SocketServer 实现网络服务器的问题
我是套接字编程的初学者,需要你的帮助。我使用 Python 文档中的 ThreadedTCPServer 示例实现了简单的回显服务器。它工作正常,但我有以下问题:
- 当客户端尝试发送零长度数据时,服务器挂起(在 socket.recv 中)。
- 当客户端发送的数据是BUF_SIZE的倍数时,服务器挂起(在socket.recv中)。
- 我不知道从外部停止服务器的正确方法。我想要一个脚本,例如 stopServer.py,当需要停止服务器时可以从服务器主机启动该脚本。我已经实现了发送到服务器端口的“STOP”命令。这种方法对我来说看起来不错,但存在安全风险。请注意,我需要一个跨平台解决方案。因此,信号可能不合适。
如果您对如何解决上述问题有任何想法,我将不胜感激。 下面列出了示例的代码。
祝你今天过得愉快! Zakhar
client.py
import sys
import socket
from common import recv
if len (sys.argv) == 1 :
print "The file to be sent is not specified"
sys.exit (1)
fname = sys.argv [1]
print "Reading '%s' file..." % fname,
f = open (sys.argv [1])
msg = f.read ()
f.close()
print "OK"
if len (msg) == 0 :
print "Nothing to send. Exit."
sys.exit (0)
print "Client is sending:"
print msg
print "len (msg)=%d" % len (msg)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.connect ( ('localhost', 9997) )
sock.sendall (msg)
print "Sending has been finished"
print "Waiting for response..."
response = recv (sock)
print "Client received:"
print response
print "len (response)=%d\n" % len (response)
sock.close ()
server.py
import threading
import SocketServer
from common import recv
class ThreadedTCPRequestHandler (SocketServer.BaseRequestHandler):
def handle(self) :
recvData = recv (self.request)
print "NEW MSG RECEIVED from %s" % self.client_address [0]
print "Data:"
print recvData
print "dataSize=%d" % len (recvData)
if recvData == "!!!exit!!!" :
print 'Server has received exit command. Exit.'
self.server.shutdown()
else :
curThread = threading.currentThread ()
response = "%s: %s" % (curThread.getName (), recvData)
self.request.sendall (response)
class ThreadedTCPServer (SocketServer.ThreadingMixIn, SocketServer.TCPServer) :
pass
if __name__ == "__main__":
HOST, PORT = "localhost", 9997
server = ThreadedTCPServer ((HOST, PORT), ThreadedTCPRequestHandler)
server.serve_forever ()
common.py
'''
Common code for both: client and server.
'''
def recv (sock) :
'''
Reads data from the specified socket and returns them to the caller.
IMPORTANT:
This method hangs in socket.recv () in the following situations (at least
on Windows):
1. If client sends zero-length data.
2. If data sent by client is multiple of BUF_SIZE.
'''
BUF_SIZE = 4096
recvData = ""
while 1 :
buf = sock.recv (BUF_SIZE)
if not buf :
break
recvData += buf
if len (buf) < BUF_SIZE : # all data have been read
break
return recvData
I am beginner in socket programming and need your help. I have implemented simple echo server using ThreadedTCPServer example from the Python documentation. It works fine, but I have the following problems:
- Server hangs (in socket.recv) when Client tries to send zero-length data.
- Server hangs (in socket.recv) when the data sent by Client is multiple of BUF_SIZE.
- I don't know the right way to stop the server from the outside. I'd like to have a script, for example, stopServer.py which can be started from the server's host when need to stop the server. I've implemented "STOP" command which is send to the server's port. This approach looks good for me, but has security risk. Note that I need a cross-platform solution. So, probably, signals are not suitable.
I will appreciate if you have any ideas how to fix the issues listed above.
The example's code is listed below.
Have a nice day!
Zakhar
client.py
import sys
import socket
from common import recv
if len (sys.argv) == 1 :
print "The file to be sent is not specified"
sys.exit (1)
fname = sys.argv [1]
print "Reading '%s' file..." % fname,
f = open (sys.argv [1])
msg = f.read ()
f.close()
print "OK"
if len (msg) == 0 :
print "Nothing to send. Exit."
sys.exit (0)
print "Client is sending:"
print msg
print "len (msg)=%d" % len (msg)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.connect ( ('localhost', 9997) )
sock.sendall (msg)
print "Sending has been finished"
print "Waiting for response..."
response = recv (sock)
print "Client received:"
print response
print "len (response)=%d\n" % len (response)
sock.close ()
server.py
import threading
import SocketServer
from common import recv
class ThreadedTCPRequestHandler (SocketServer.BaseRequestHandler):
def handle(self) :
recvData = recv (self.request)
print "NEW MSG RECEIVED from %s" % self.client_address [0]
print "Data:"
print recvData
print "dataSize=%d" % len (recvData)
if recvData == "!!!exit!!!" :
print 'Server has received exit command. Exit.'
self.server.shutdown()
else :
curThread = threading.currentThread ()
response = "%s: %s" % (curThread.getName (), recvData)
self.request.sendall (response)
class ThreadedTCPServer (SocketServer.ThreadingMixIn, SocketServer.TCPServer) :
pass
if __name__ == "__main__":
HOST, PORT = "localhost", 9997
server = ThreadedTCPServer ((HOST, PORT), ThreadedTCPRequestHandler)
server.serve_forever ()
common.py
'''
Common code for both: client and server.
'''
def recv (sock) :
'''
Reads data from the specified socket and returns them to the caller.
IMPORTANT:
This method hangs in socket.recv () in the following situations (at least
on Windows):
1. If client sends zero-length data.
2. If data sent by client is multiple of BUF_SIZE.
'''
BUF_SIZE = 4096
recvData = ""
while 1 :
buf = sock.recv (BUF_SIZE)
if not buf :
break
recvData += buf
if len (buf) < BUF_SIZE : # all data have been read
break
return recvData
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不懂Python,但我会根据我的套接字编程知识尝试回答。
零字节消息不会导致“sock.recv”出现。请参阅此处 进行解释。如果sock.recv返回长度为0,则表明对方已断开TCP连接。
该行如何确定所有数据已被读取。 TCP receive 调用不是 TCP send 调用之间的 1-1 映射,即客户端在 1 个 send 调用中发送的内容可以在多个 receive 调用中接收。
当您发送多个 BUF_SIZE(即 2 * BUF_SIZE)时,您可能会一次性收到所有内容。那时,您的服务器将挂起为
len(buf) > BUF_SIZE
并且你会陷入 sock.recv 中。尝试&弄清楚如何使用非阻塞套接字。I don't know python but I will try and answer based on my socket programming knowledge.
A zero byte message will NOT cause "sock.recv" to come out. Refer here for an explanation. If sock.recv returns with length 0, it is an indication that the other side has disconnected the TCP connection.
How does this line determine that ALL data has been read. TCP recv call is not a 1-1 mapping between TCP send call i.e. what client sends in 1 send call can be received in multiple recv calls.
When you send multiple of BUF_SIZE i.e lets say 2 * BUF_SIZE, it is possible that you might receive all of it in one go. At that point, your server would hang as
len(buf) > BUF_SIZE
and you would get stuck in sock.recv. Try & figure out how to use non-blocking sockets.经过一些实验,我发现以下内容:
需要在 common.recv 中注释以下 2 行(错误):
After some experiments I found the following:
Need to comment the following 2 lines in common.recv (bug):