如何保持套接字打开直到客户端关闭?
我有一个简单的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机器上也试过。服务器只接收到一条消息,然后在接收第二条消息时出现了错误。我刚开始学习Python的网络编程,但我觉得服务器可能因为某种原因关闭了连接。请问我该怎么解决这个问题呢?
3 个回答
这里有一个类似的问题,链接是 错误: [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
我不确定一个套接字对象是否只能发送和接收一次数据。
更新 我认为问题出在每个客户端套接字接收数据的能力上,这取决于固定的缓冲区大小; 这就是为什么上面的第二段代码可以工作,从而在服务器上创建新的客户端连接套接字。但这样会消耗很多套接字。
相反,以下代码通过检查使用的大小来解决了这个问题。如果超过了给定的数量,它会在客户端创建一个新的套接字,但确保消息被发送;实际上,问题出在服务器代码上,但我修复了它。
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
试试看。这使用的是同一个套接字。
我首先要承认,自从我上次使用过 SocketServer
已经过去很多年了,所以可能有更合适的方法来解决你的问题。
注意,你的客户端打开了一个连接,然后发送了三组数据,也接收了三组数据。(希望 TCP 协议栈在你调用 receive()
方法时,会把缓冲的数据一次性发送出去。)
你的服务器期望能够完整处理一个客户端的连接,从开始到结束,这个过程是通过 SocketServer
的回调机制来实现的。你现在的类只做了一点输入输出操作,然后就 结束 了。你只需要扩展你的服务器回调,让它做更多的事情:
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
方法会返回 ''
(空字符串),所以我把 .strip()
移到了 recv
之后,这样就不会因为客户端只发送了空格而误报了。