0

我是套接字编程的初学者,需要你的帮助。我已经使用 Python 文档中的 ThreadedTCPServer 示例实现了简单的回显服务器。它工作正常,但我有以下问题:

  1. 当客户端尝试发送零长度数据时,服务器挂起(在 socket.recv 中)。
  2. 当客户端发送的数据是 BUF_SIZE 的倍数时,服务器挂起(在 socket.recv 中)。
  3. 我不知道从外部停止服务器的正确方法。我想要一个脚本,例如 stopServer.py ,它可以在需要停止服务器时从服务器的主机启动。我已经实现了发送到服务器端口的“STOP”命令。这种方法对我来说看起来不错,但存在安全风险。请注意,我需要一个跨平台的解决方案。因此,信号可能不合适。

如果您对如何解决上面列出的问题有任何想法,我将不胜感激。该示例的代码如下所示。

祝你今天过得愉快!扎哈尔

客户端.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 ()

服务器.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 ()

常见的.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
4

2 回答 2

2

我不知道python,但我会根据我的套接字编程知识尝试回答。

零字节消息不会导致“sock.recv”出现。请参阅此处以获取说明。如果 sock.recv 返回长度为 0,则表明对方已断开 TCP 连接。

if len (buf) < BUF_SIZE

此行如何确定已读取所有数据。TCP recv 调用不是 TCP send 调用之间的 1-1 映射,即客户端在 1 个 send 调用中发送的内容可以在多个 recv 调用中接收。

当您发送多个 BUF_SIZE 即假设 2 * BUF_SIZE 时,您可能会一次性收到所有这些。那时,你的服务器会挂起len(buf) > BUF_SIZE,你会卡在 sock.recv 中。尝试并弄清楚如何使用非阻塞套接字。

于 2010-10-02T15:58:39.103 回答
0

经过一些实验,我发现以下内容:

  1. 需要将 common.recv 重命名为 common.recvall
  2. 需要在common.recv(bug)中注释以下2行:

    if len (buf) < BUF_SIZE : # all data have been read
    break
    
  3. 仅当发送到服务器的数据可以通过服务器端的 1 个 socket.recv 调用读取时,此示例才有效。所以,发送的数据必须小于BUF_SIZE。否则,客户端和服务器在他们的 sock.recv 调用中都处于死锁状态。这是因为对共享资源(套接字)的并发访问。为了解决这个问题,客户端必须监听不同端口的回复。
于 2010-10-17T11:58:42.753 回答