我目前正在使用Python 3.x制作简单的服务器。我正在使用线程池,因为在任何给定时间都可能连接大量客户端。客户端将json对象发送到服务器,然后在其中解析并处理该对象。但是,当我从客户端使用sendall发送多个json对象时,服务器挂起,并且不会处理handle_client函数中的json.loads。
这只是一个示例,因为我正在学习如何在python中使用套接字和线程池。最终,我需要保持持久的连接。人们对它为什么挂断的任何解释表示赞赏。谢谢!
服务器
import sys, socket, threading, json, time, concurrent.futures
HOST = socket.gethostbyname(socket.gethostname())
PORT = 65000
TIMEOUT = 5
MAX_CLIENTS = 5
BUFFER_SIZE = 1024
ENCODING_TYPE = 'utf-8'
clients = []
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.settimeout(TIMEOUT)
server.setblocking(0)
server.listen(MAX_CLIENTS)
print("Server started successfully")
Pool = concurrent.futures.ThreadPoolExecutor(max_workers=5)
def handle_client(client):
if client not in clients:
clients.append(client)
print('%s clients connected.' % len(clients))
while True:
data = client.recv(BUFFER_SIZE).decode(ENCODING_TYPE)
if data:
jsonObj = json.loads(data)
client.sendall('Keep up the great work!'.encode(ENCODING_TYPE))
else:
clients.remove(client)
client.close()
print('%(name)s is a %(occupation)s!' % {'name': jsonObj['name'], 'occupation': jsonObj['occupation']})
while True:
try:
client, addr = server.accept()
client.setblocking(0)
Pool.submit(handle_client, client)
Pool.shutdown(wait=False)
except BlockingIOError:
pass
server.close()
print('Server shutdown')
sys.exit()
客户
import sys, socket, json, time
HOST = socket.gethostbyname(socket.gethostname())
PORT = 65000
BUFFER_SIZE = 1024
ENCODING_TYPE = 'utf-8'
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))
data1 = {
'name': 'John Doe',
'age': 23,
'occupation': 'QA Engineer',
'employer': 'Samsung'
}
data2 = {
'name': 'Jane Roe',
'age': 32,
'occupation': 'HR Representative',
'employer': 'Samsung'
}
packet1 = json.dumps(data1)
packet2 = json.dumps(data2)
client.sendall(packet1.encode(ENCODING_TYPE))
client.sendall(packet2.encode(ENCODING_TYPE))
while True:
response = client.recv(BUFFER_SIZE).decode(ENCODING_TYPE)
print(response)
client.close()
print('Client terminated')
答案 0 :(得分:0)
这里有很多问题,但我认为您的问题始于这一行:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
了解此行的含义很重要。您正在创建一个TCP套接字。 TCP是“面向流”的协议。这意味着它没有任何“数据包”的概念。 send()
和sendall()
将字节推入套接字,而recv()
将字节拉出套接字。在将字节推入套接字后,TCP不会努力跟踪字节来自哪个“ send()
”。
如果a
和b
都是bytes
个对象,则sendall(a); sendall(b)
等同于sendall(a+b)
(存在明显的性能差异,我有意忽略)。同样,recv(1024)
的意思是“从套接字中获取下一个1024字节,如果还没有1024字节,则给我少于这个数目”。如果对等方连续执行两次发送,则recv可能会将它们组合在一起,也可能不会合并,具体取决于时间(以及其他因素,例如Nagle's algorithm)。同样,一个非常大的发送可能会拆分为多个recv(即使缓冲区大小足够大)。
通常,在TCP之上设计协议时,必须注意“文书工作”的某些方面,以确保一切顺利进行:
recv()
的结果串联起来。对等方必须准备好妥善处理部分消息,例如:
.decode()
UnicodeError
来结束。json.loads()
和ValueError
处失败。recv
失败之前调用BlockingIOError
是不够的,因为由于性能原因,以后的数据包可能已被延迟或故意保留(小数据包相对昂贵)。接收方必须实际检查到目前为止收到的数据,并检查它是否是完整的消息。最后,这是我对您的服务器代码的其他一些看法: