【问题标题】:How to keep a socket open until client closes it?如何保持套接字打开直到客户端关闭它?
【发布时间】:2012-01-27 12:25:36
【问题描述】:

我有简单的 python 服务器和客户端。

服务器:

import SocketServer
import threading


class MyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()
        print str(self.client_address[0]) + " wrote: "
        print self.data
        self.request.send(self.data.upper())


if __name__ == "__main__":
    HOST, PORT = "localhost", 3288
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
    server.serve_forever()

客户:

import socket
import sys
from time import sleep

HOST, PORT = "localhost", 3288
data = "hello"

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    sock.connect((HOST, PORT))
    sock.send(data + "\n")
    received = sock.recv(1024)

    sleep(10)

    sock.send(data + "\n")
    received = sock.recv(1024)

    sleep(10)

    sock.send(data + "\n")
    received = sock.recv(1024)

finally:
    sock.close()

这是我得到的输出:

服务器:

>python server.py
127.0.0.1 wrote:
hello

客户:

>python client.py
Traceback (most recent call last):
  File "client.py", line 18, in <module>
    received = sock.recv(1024)
socket.error: [Errno 10053] An established connection was aborted by the software in your host machine

我也在linux机器上试过了。服务器只收到一条消息,然后我在第二条消息的 recv 语句中收到错误。我刚刚开始在 python 上学习网络,但我认为服务器出于某种原因正在关闭套接字。我该如何纠正这个问题?

【问题讨论】:

标签: python networking


【解决方案1】:

为每个连接创建一个MyTcpHandler对象,并调用handle处理客户端。当handle 返回时连接关闭,因此您必须在handle 方法中处理来自客户端的完整通信:

class MyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        while 1:
            self.data = self.request.recv(1024)
            if not self.data:
                break
            self.data = self.data.strip()
            print str(self.client_address[0]) + " wrote: "
            print self.data
            self.request.send(self.data.upper())

注意:recv 在客户端关闭连接时返回'',所以我将.strip() 移动到recv 之后,因此不会因为客户端只发送空白而导致误报。

【讨论】:

  • 但这似乎不适用于多连接
  • @qichao_he 使用ThreadingTCPServer 处理多个连接。
  • @MarkTolonen 是的,谢谢!我又看了一遍文档,找到了解决办法。
【解决方案2】:

我首先要承认,自从我上次使用 SocketServer 已经有好几年了,所以可能有更多惯用的方法来解决您的问题。

请注意,您的客户端打开单个连接并发送三组数据并接收三组数据。 (希望一旦您在套接字上调用receive(),TCP 堆栈将发送缓冲数据。)

当从SocketServer 回调机制调用它时,您的服务器期望从头到尾完全处理客户端连接。您当前的班级做了一点 IO,然后退出。你只需要扩展你的服务器回调来做更多的事情:

class MyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()
        print str(self.client_address[0]) + " wrote: "
        print self.data
        self.request.send(self.data.upper())
        foo = self.request.recv(1024).strip()
        self.request.send(foo.lower())
        bar = self.request.recv(1024).strip()
        self.request.send("goodbye " + bar)

【讨论】:

    【解决方案3】:

    这里有类似的问题error: [Errno 10053]

    我也尝试了同样的事情并得到了同样的错误。

    如果有这样一个简单的代码来演示这个错误:

    import socket 
    
    host = 'localhost' 
    port = 5001 
    size = 102400
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.connect((host,port))
    for msg in ['Hello, world','Test','anything goes here']:
        s.send(msg)
        data = s.recv(size)
        print 'Received:', data 
    s.close()  
    

    如果您创建一个套接字对象,并且它可以从服务器发送和回显它的 amt,以查看它接收了多少,如果您改变它,例如 1024 到 102400(在此代码中); 这意味着套接字不应关闭,但在我的 Windows 操作系统中,服务器端会继续监听并打印客户端发送的任何数据,但在客户端会出现此错误;

    但是,如果客户端只能连接一次,并且只能发送和接收一次,那么它就是这样设计的。尝试这个没有任何错误:

    for msg in ['Hello, world','Test','anything goes here']:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
        s.connect((host,port))
        s.send(msg)
        data = s.recv(size)
        s.close()
        print 'Received:', data
    

    我不确定一个套接字对象是否只工作一次来发送和接收数据。

    更新 我认为问题在于每个客户端套接字根据固定缓冲区大小接收数据的容量; 这就是为什么上面的第二个代码 sn-p 起作用,从而在服务器上创建新的客户端连接套接字。但是那样的话很多套接字会被用完。

    下面的代码通过检查正在使用的大小来解决这个问题。如果超过给定的数量,它会在客户端创建一个新的套接字,但确保消息被发送;实际上问题出在服务器代码上,但已修复。

    大小 = 10

    这是对代码的快速婴儿尝试。我相信你会理解并优化它!

    客户端代码:

    messag = ['Hello, world', 'Test', 'anything goes here']
    
    def client_to_server(messag,host,port,size):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((host, port))
        countmsg = 0
        restmsg = ''
        for msg in messag:
            strl = tmsg = msg
            if len(restmsg):
                tmsg = restmsg + ' ' + msg
            countmsg = len(tmsg)
            if countmsg <= size:
                pass
            else:
                restmsg = tmsg[size:]
                tmsg = tmsg[:size]
                #s.close()
                countmsg = len(tmsg)
                #s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
                #s.connect((host, port))
            print 'Sending to server msg {}'.format(tmsg)
            s.send(tmsg)
            # s.settimeout(1)
            try: 
                data = s.recv(size)
                print 'Received:', data
                if strl == data:
                    print strl,data
                    countmsg = 0
                    restmsg = ''
            except (socket.error), e: 
                print e.args,e.message
                s.close()
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
                s.connect((host, port))
        s.close()
        if restmsg: 
            client_to_server([restmsg],host,port,size)
        return
    
    
    client_to_server(messag,host,port,size)
    

    服务器代码:

    size = 1024  #This has to be bigger than client buf size!
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((host, port)) 
    s.listen(backlog)
    while True:
            #this is what accepts and creates a P2P dedicated client socket per socket
            client, address = s.accept()
            try: 
                data = client.recv(size)
                while data or 0:
                    print "Client sent {} | Server sending data to client address {}".format(data, address)
                    client.send(data)
                    data = client.recv(size)
                else: client.close()
            except (socket.error), e: 
                client.close()
                print e.args, e.message
    

    试试看。这使用相同的套接字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-05
      • 2020-10-20
      • 1970-01-01
      • 2016-08-06
      相关资源
      最近更新 更多