Python 如何保持套接字打开直到客户端关闭它?

Python 如何保持套接字打开直到客户端关闭它?,python,networking,Python,Networking,我有简单的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: "

我有简单的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()
>python server.py
127.0.0.1 wrote:
hello
客户:

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 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
以下是我得到的输出:

服务器:

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()
>python server.py
127.0.0.1 wrote:
hello
客户:

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 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
>python client.py
回溯(最近一次呼叫最后一次):
文件“client.py”,第18行,在
已接收=sock.recv(1024)
socket.error:[Errno 10053]主机中的软件中止了已建立的连接

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

我首先要承认,我上次使用
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)

为每个连接创建一个
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
在客户端关闭连接时返回
'
,因此我在
recv
之后移动了
.strip()
,因此不会因为客户端只发送空白而出现假警报。

这里有类似的问题

我也试过同样的方法,但也犯了同样的错误

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

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
我不确定一个套接字对象是否只工作一次来发送和接收数据

更新 我认为问题在于每个客户端套接字按照固定的缓冲区大小接收数据的容量; 这就是为什么上面的第二个代码段可以工作,从而在服务器上创建新的客户端连接套接字。但是那样的话,很多插座都会用光

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

尺寸=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)

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

这可能会有所帮助:但这似乎不适用于多个套接字connection@qichao_he使用
threadingcpserver
处理多个连接。@MarkTolonen是的,谢谢!我再次查看了文档,找到了解决方案。