本文勿动,被 python之socket编程(TCP)粘包 ,python之TCP recv()接收数据长度为0表示远端socket已close 等文章引用
概述
在前文的服务器代码,只能 连接一个客户端,发送一次数据,就close了,这显然是不合理的,服务器必须可以 连接多个客户端,多次发送的数据
优化服务器端代码
服务器端可以接收客户端多次发送的数据
import socket
s = socket.socket()
s.bind(('0.0.0.0', 9999))
s.listen(5)
print('开始监听')
#在这里写一个死循环,永远接收客户端请求
while True:
conn, address = s.accept()
print('接收到客户端请求')
print('conn类型',type(conn))
print('address类型',type(address),address)
conn.sendall('server is ok!'.encode('utf-8'))
while True:
print(1)
data=conn.recv(1024)
#当接收数据长度为0时,表示远端socket已经close
print('接收数据长度:%d'%len(data))
if data:
print("来自%s:%s的消息:"%(address[0],address[1]),data.decode('utf-8'))
else:
break
conn.close()
print('\n\n-------------------------')
将服务器端在一台电脑运行
1. 客户端代码如下
#coding=utf-8
import socket
s = socket.socket()
s.connect(('127.0.0.1', 9999))
data=s.recv(1024)
print('来自server的消息:',data.decode('utf-8'))
s.sendall('name:lilei'.encode('utf-8'))
s.close()
将客户端在另一台电脑上,反复执行上面客户端,观察服务器端打印结果,得知服务器端一直在运行,没有结束
2. 在服务器端接收时,客户端终止
在服务器端接收时,客户端终止,服务器端会报错
#coding=utf-8
import socket,time
s = socket.socket()
s.connect(('127.0.0.1', 9999))
data=s.recv(1024)
print('来自server的消息:',data.decode('utf-8'))
s.sendall('name:lilei'.encode('utf-8'))
time.sleep(10)
s.close()
执行客户端程序,在休眠期间直接 关闭客户端窗口,服务器端抛异常如下:
Traceback (most recent call last):
File "c:/Users/mym/Desktop/python/tcp_test.py", line 16, in <module>
data=conn.recv(1024)
ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
优化服务器端代码
在接收代码处加try…except…finally
import socket
s = socket.socket()
s.bind(('0.0.0.0', 9999))
s.listen(5)
print('开始监听')
#在这里写一个死循环,永远接收客户端请求
while True:
conn, address = s.accept()
print('接收到客户端请求')
print('conn类型',type(conn))
print('address类型',type(address),address)
conn.sendall('server is ok!'.encode('utf-8'))
try:
while True:
print(1)
data=conn.recv(1024)
#当接收数据长度为0时,表示远端socket已经close
print('接收数据长度:%d'%len(data))
if len(data)>0:
print("来自%s:%s的消息:"%(address[0],address[1]),data.decode('utf-8'))
else:
break
except BaseException as e:
#当远端程序直接退出(没有执行socket的close()),会抛出异常,捕捉异常是为了防止服务器端退出
print(e)
finally:
if conn:
conn.close()
print('\n\n-------------------------')
缺点
代码:
conn, address = s.accept()
是服务器阻塞等待客户端,当服务器与一个客户端建立连接后,开始执行下面的代码:
print('接收到客户端请求')
print('conn类型',type(conn))
print('address类型',type(address),address)
conn.sendall('server is ok!'.encode('utf-8'))
try:
while True:
print(1)
data=conn.recv(1024)
#当接收数据长度为0时,表示远端socket已经close
print('接收数据长度:%d'%len(data))
if len(data)>0:
print("来自%s:%s的消息:"%(address[0],address[1]),data.decode('utf-8'))
else:
break
except BaseException as e:
#当远端程序直接退出(没有执行socket的close()),会抛出异常,捕捉异常是为了防止服务器端退出
print(e)
finally:
conn.close()
print('\n\n-------------------------')
在真实的服务器代码中,上面处理业务功能的代码可能很长,需要若干时间才能完成,当前的服务器是单进程 单线程 的,不是 并发的web应用,就会导致后面的客户端等待,无法满足很多用户访问,这显然是不合理的