如何在客户端关闭套接字之前保持套接字打开?

时间:2011-12-25 02:52:07

标签: 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: "
        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上学习网络,但我认为服务器出于某种原因关闭了套接字。我该如何纠正?

3 个答案:

答案 0 :(得分:22)

为每个连接创建一个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,因此客户端仅发送错误警报白色空间。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

这里遇到类似的问题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()  

如果你创建一个套接字对象,它可以从服务器发送和回显,以查看接收器的数量,如果你改变它,比如说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

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

<强>更新 我认为问题是每个客户端套接字按照固定的buffersize接收数据的容量; 这就是为什么上面的第二个代码片段工作,从而在服务器上创建新的客户端连接套接字。但是那样很多套接字都会被用完。

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

size = 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

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