动态导入
方法1:import方式
#!/usr/bin/env python
# -*- coding:utf-8 -*-
mod = __import__('lib.aa')#__import__只到lib
print(mod)
c_instance = getattr(mod.aa,'C')
c_obj = c_instance()
print(c_obj.name)
#输出
<module 'lib' from '/root/py/学习/day8/动态导入/lib/__init__.py'>
liyanan
方法2:importlib方式
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import importlib
mod = importlib.import_module('lib.aa')#到达aa这个目标
print(mod)
c_instance = mod.C
c_obj = c_instance()
print(c_obj.name)
#输出
<module 'lib.aa' from '/root/py/学习/day8/动态导入/lib/aa.py'>
liyanan
小结:
1、import方式是python内置函数,是python自己用的,而且知道第一层,所以极力不推荐
2、importlib这种方式是官方推荐的,用起来比较简单,而且导入到那哪里就到哪里,极力推荐
断言
python中断言,就是做一些程序的检查工作,就是在执行之前需要做的一些检查,比如类似于安检一样,合格的就能过,不合格的就不能过。也类似于银行转账工作,真正的转账之前是不是要检查用户各方面,是不是账号密码是不是都没有问题,转的钱必须没有问题,所以你在这个操作之前做一下检查。
作用:断言被用作你接下来的程序执行,如果后面程序依赖于前面的程序,后面的程序有很重要,就是后面的程序执行肯定不能出错,所以在执行之前要做检查工作。
断言的使用:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class C(object):
def __init__(self):
self.name = 'liyanan'
c_obj = C()
assert c_obj.name =='liyanan'#断言的格式
print('断言没出错')
#输出
断言没出错
断言出错:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class C(object):
def __init__(self):
self.name = 'liyanan'
c_obj = C()
assert c_obj.name =='li'#断言的格式
print('断言有没有出错呢?')
#输出
Traceback (most recent call last):
File "/root/py/学习/day8/断言/断言.py", line 10, in <module>
assert c_obj.name =='li'#断言的格式
AssertionError
断言错误,没有运行到下一步的‘print’,用于重要程序的阻断和判断。
socket问题
ssh的例子在上一篇day7中讲到了,但是有一个问题,我们再演示一遍,结果如下:
输入pwd没有显示出linux当前的目录,而是附带了上个命令的结果,原因是大小只设置了缓冲区1024。服务端第一次全部发送给客户端,客户端只接收自己部分的字节数,剩下的字节数被存储在 IO缓冲区 中,下一次你再用send的时候,你以为接收的是新的数据,其实不是,它会先把缓冲区里的数据发出去,然后你的新数据再放到缓冲区中,直到缓冲区满了再发出去。这就导致结果会一直推后,设置成更大的缓存区也不是个很好的办法。
我们可以让客户端多收几次,但是,客户端需要收多少次,才能把这个命令返回的结果全部收回来呢?并且怎么确定这条命令返回的结果已经被全部收回来了呢?
cocket接收大数据
解决客户端收多少次,我们可以引入大小的概念,服务端给客户端发数据之前,先计算一下给客户端要发多少数据,我先判断 len 一下,就 ok 了,先让客户端知道服务端发送过来的大小,比如说发过来的是5k大小,客户端接收到了这个5k大小以后,就知道需要接收多少次了,循环接收,直到5k数据全部接收完毕为止。
客户端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
client = socket.socket()
client.connect(("0.0.0.0", 6969))
while True:
msg = input(">>>:").strip()
if len(msg) == 0: continue
client.send(msg.encode('utf-8'))
msg_res_size = client.recv(1024)#接受命令的长度
print('命令结果大小',msg_res_size.decode())
recevied_size = 0 #接收的数据开始大小
recevied_data = b''#客户端每次发来内容的计数器
while recevied_size < int(msg_res_size.decode()): #当接收的数据大小 小于 客户端发来的数据
msg_res = client.recv(1024)
recevied_size+=len(msg_res)#每次收到的服务端的数据有可能小于1024,所以必须用len判断
print(recevied_size)
recevied_data+=msg_res
else:
print(recevied_data.decode('utf-8','ignore'))
print('接收大小',recevied_size)
client.close()
服务端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket,time
import os # 导入os模块
sever = socket.socket()
sever.bind(("0.0.0.0", 6969))
sever.listen()
while True:
conn, addr = sever.accept()
print("电话来了",addr)
while True:
data = conn.recv(1024)
if not data: break
print('执行指令',data)
msg_res = os.popen((data.decode())).read() # 调用linux命令
print('发送之前',len(msg_res))
if len(msg_res) ==0:
msg_res = '输入错误'
conn.send(str(len(msg_res.encode())).encode())#发送大小给客户端
conn.send(msg_res.encode()) # 执行的命令返回值
print('send done')
sever.close()
输出
>>>:ifconfig
ifconfig
命令结果大小 1280ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.224.128 netmask 255.255.255.0 broadcast 192.168.224.255
inet6 fe80::c9a6:298e:c35b:36c5 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:3f:08:7e txqueuelen 1000 (Ethernet)
RX packets 3015 bytes 307695 (300.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1954 bytes 647060 (631.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 194 bytes 17900 (17.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 194 bytes 17900 (17.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.2
Traceback (most recent call last):
File "/root/py/学习/day8/黏包问题/client.py", line 16, in <module>
while recevied_size < int(msg_res_size.decode()): #当接收的数据大小 小于 客户端发来的数据
ValueError: invalid literal for int() with base 10: '1280ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n inet 192.168.224.128 netmask 255.255.255.0 broadcast 192.168.224.255\n inet6 fe80::c9a6:298e:c35b:36c5 prefixlen 64
Process finished with exit code 1
出错了,出错的原因是是服务端两次发送给客户端的数据粘在一起了。
黏包问题的解决
1、sleep,
这个样子就可以使缓冲区超时,就不在等下一次的了,这样就可以和下一条命令隔离开了
服务器端:
import socket,time
import os # 导入os模块
sever = socket.socket()
sever.bind(("0.0.0.0", 6969))
sever.listen()
while True:
conn, addr = sever.accept()
print("电话来了",addr)
while True:
data = conn.recv(1024)
if not data: break
print('执行指令',data)
msg_res = os.popen((data.decode())).read() # 调用linux命令
print('发送之前',len(msg_res))
if len(msg_res) ==0:
msg_res = '输入错误'
conn.send(str(len(msg_res.encode())).encode())#发送大小给客户端
time.sleep(0.5)
conn.send(msg_res.encode()) # 执行的命令返回值
print('send done')
sever.close()
输出:
>>>:ls
ls
命令结果大小 32
32
client.py
__init__.py
server.py
接收大小 32
>>>:ifconfig
ifconfig
命令结果大小 1280
1024
1280
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.224.128 netmask 255.255.255.0 broadcast 192.168.224.255
inet6 fe80::c9a6:298e:c35b:36c5 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:3f:08:7e txqueuelen 1000 (Ethernet)
RX packets 3192 bytes 324404 (316.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2062 bytes 668844 (653.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 233 bytes 23213 (22.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 233 bytes 23213 (22.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:83:37:c9 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
接收大小 1280
>>>:
这个方法虽然可以解决黏包问题,但是需要等待0.5s最少。在一些场景中不能使用。我们可以通过下面的方法。
2、在服务端来一个等待客户端确认,就ok了,这个确认不需要我们用户输入,而是客户端自动的给你来这个响应,就是说,客户端自动的写好代码,自动的给服务器一个响应,只要收到服务端的数据大小,我就立刻给服务器一个响应,就是在第一次send和第二次send之前插入一个交互,就能把数据分开了。
客户端代码改进:
import socket
client = socket.socket()
client.connect(("0.0.0.0", 6969))
while True:
msg = input(">>>:").strip()
if len(msg) == 0: continue
client.send(msg.encode('utf-8'))
msg_res_size = client.recv(1024)#接受命令的长度
print('命令结果大小',msg_res_size.decode())
client.send('我准备好了接收了,可以发射'.encode())#改进黏包
recevied_size = 0 #接收的数据开始大小
recevied_data = b''#客户端每次发来内容的计数器
while recevied_size < int(msg_res_size.decode()): #当接收的数据大小 小于 客户端发来的数据
msg_res = client.recv(1024)
recevied_size+=len(msg_res)#每次收到的服务端的数据有可能小于1024,所以必须用len判断
print(recevied_size)
recevied_data+=msg_res
else:
print(recevied_data.decode('utf-8','ignore'))
print('接收大小',recevied_size)
client.close()
服务端改进:
import socket,time
import os # 导入os模块
sever = socket.socket()
sever.bind(("0.0.0.0", 6969))
sever.listen()
while True:
conn, addr = sever.accept()
print("电话来了",addr)
while True:
data = conn.recv(1024)
if not data: break
print('执行指令',data)
msg_res = os.popen((data.decode())).read() # 调用linux命令
print('发送之前',len(msg_res))
if len(msg_res) ==0:
msg_res = '输入错误'
conn.send(str(len(msg_res.encode())).encode())#发送大小给客户端
#time.sleep(0.5)
clent_ack = conn.recv(1024)#改进黏包,等待客户端确认
conn.send(msg_res.encode()) # 执行的命令返回值
print('send done')
sever.close()
文件的发送
用socket实现文件下载,思路如下:
1、读取文件名
2、检测文件是否存在
3、打开文件
4、检测文件大小
5、发送文件大小给客户端
6、等客户确认
7、开始边读边发数据
8、发送md5值给客户端校验
功能 实现:
服务端:(获取命令和文件名->判断文件是否存在->打开文件->获取文件大小->发送文件大小给客户端->等待客户端确认->边读边发)
import socket,time
import os # 导入os模块
sever = socket.socket()
sever.bind(("0.0.0.0", 6969))
sever.listen()
while True:
conn, addr = sever.accept()
print("电话来了",addr)
while True:
data = conn.recv(1024)
if not data: break
print('执行指令',data)
msg,filename = data.decode().split()#接受客户端发过来的命令和文件名
print(filename)
if os.path.isfile(filename):#文件存在
with open(filename,'rb') as f:
file_size = os.stat(filename).st_size #获取文件大小
conn.send(str(file_size).encode())#发送文件大小
conn.recv(1024)
for line in f:
conn.send(line) #边读边发送给客户端
print('send done')
sever.close()
客户端(判断是否是下载命令(get) ->发送下载命令和文件名 ->获取文件大小->发送确认信息->判断时候已经全部接收)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
client = socket.socket()
client.connect(("0.0.0.0", 6969))
while True:
msg = input(">>>:").strip()
if len(msg) == 0: continue
if msg.startswith('get'):
client.send(msg.encode())#发送下载的命令和文件名
server_respose = client.recv(1024)#接收文件大小
print('server response:',server_respose)
client.send('ready to recv file'.encode())#发送确认信息
file_total_size = int(server_respose.decode())
revived_size = 0#初始化大小
filename = msg.split()[1]#获取文件名
with open(filename+'.cp','wb')as f:
while revived_size<file_total_size:#接收文件的大小小于总文件大小
data = client.recv(1024)
revived_size+=len(data)#接收大小
f.write(data)
else:
print(file_total_size,revived_size)
print('文件接收完了')
client.close()
然后加上md5的验证
服务端:(生成md5的对象->计算MD5值->生成16进制的形式->编码后发送给客户端)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket,time,hashlib
import os # 导入os模块
sever = socket.socket()
sever.bind(("0.0.0.0", 6969))
sever.listen()
while True:
conn, addr = sever.accept()
print("电话来了",addr)
while True:
data = conn.recv(1024)
if not data: break
print('执行指令',data)
msg,filename = data.decode().split()#接受客户端发过来的命令和文件名
print(filename)
if os.path.isfile(filename):#文件存在
m = hashlib.md5()#(md5改动)生成md5的对象
with open(filename,'rb') as f:
file_size = os.stat(filename).st_size #获取文件大小
conn.send(str(file_size).encode())#发送文件大小
conn.recv(1024)#等待ack
for line in f:
m.update(line)#(md5改动)计算md5值
conn.send(line) #边读边发送给客户端
print('file md5',m.hexdigest())
conn.recv(1024)#(md5改动)等待客户确认发送md5值
print('send done')
sever.close()
客户端:(生成MD5值->计算接收的数据的MD5值->生成接收数据的MD5值16进制的形式->发送接收MD5值确认信息->接收客户端的MD5值->客户端和服务端的MD5值做比较)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket,hashlib
client = socket.socket()
client.connect(("0.0.0.0", 6969))
while True:
msg = input(">>>:").strip()
if len(msg) == 0: continue
if msg.startswith('get'):
client.send(msg.encode())#发送下载的命令和文件名
server_respose = client.recv(1024)#接收文件大小
print('server response:',server_respose)
client.send('ready to recv file'.encode())#发送确认信息
file_total_size = int(server_respose.decode())
revived_size = 0#初始化大小
filename = msg.split()[1]#获取文件名
m = hashlib.md5()#(md5改动)生成md5对象
with open(filename+'.cp','wb')as f:
while revived_size<file_total_size:#接收文件的大小小于总文件大小
data = client.recv(1024)
revived_size+=len(data)#接收大小
m.update(data)#(md5改动)计算数据接收的md5值
f.write(data)
else:
print(file_total_size,revived_size)
client_md5_vault = m.hexdigest()#(md5改动)生成接收数据的md5值16进制形式
client.send('ready to recv file md5 value'.encode())
server_md5_vault = client.recv(1024)#(md5改动)接收服务端发送的md5值
if client_md5_vault == server_md5_vault.decode():#(md5改动)两个md5进行比较
print('文件接收完了')
else:
print(client_md5_vault,server_md5_vault.decode())
client.close()
小结:
1、上传和下载都是以客户端或者服务端加载文件,然后另外一边接收再写入文件。
2、解决粘包问题,在接收数据大小后需要等待确认信息。
3、看文件能都上传和下载,应该用MD5值去校验。
4、创建一个无限大的文件,请用:dd if=/dev/sda1 of=文件名,比如创建test.txt,则:dd if=/dev/sda1 of=test.txt
5、获取一个文件的大小:os.stat(文件名).st_size
改良md5的黏包问题
之前解决粘包的方法,是客户端发送一个请求,等待服务端的确认的这样的一个笨方法。下面我们用另外一种方法:就是客户端已经知道可接收多少数据了,既然客户端已经知道接收多少数据了,那么客户端在接收数据的时候,正好接收已经知道的数据,不就ok了吗?就是说我循环了正好是收到已经知道的那些数据。比如:我要发5M的数据,我正好收到5M的数据,然后就不往下再收了,因为它有可能跟MD5值黏在一块了,本来说是发5M文件,结果你发了5.1M,那么客户端正好收5M的话,那客户端的0.1M是不是就不收了,不收了之后我就把客户端把文件存下来,再来recive一下,下面recive的正好是0.1M。
代码实现:
服务端:(生成md5对象->发送的数据生成MD5值->发送MD5 值)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket,time,hashlib
import os # 导入os模块
sever = socket.socket()
sever.bind(("0.0.0.0", 6969))
sever.listen()
while True:
conn, addr = sever.accept()
print("电话来了",addr)
while True:
data = conn.recv(1024)
if not data: break
print('执行指令',data)
msg,filename = data.decode().split()#接受客户端发过来的命令和文件名
print(filename)
if os.path.isfile(filename):#文件存在
m = hashlib.md5()#(md5改动)生成md5的对象
with open(filename,'rb') as f:
file_size = os.stat(filename).st_size #获取文件大小
conn.send(str(file_size).encode())#发送文件大小
conn.recv(1024)#等待ack
for line in f:
m.update(line)#(md5改动)计算md5值
conn.send(line) #边读边发送给客户端
print('file md5',m.hexdigest())
#conn.recv(1024)#(md5改动)等待客户确认发送md5值
conn.send(m.hexdigest().encode())#((md5改良))生成md5值并发送给客户端
print('send done')
sever.close()
客户端:(文件大小-接收大小是否大于1024 ->获取size值->recive(size)->下面再次recive时就是MD5值了)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket,time,hashlib
import os # 导入os模块
sever = socket.socket()
sever.bind(("0.0.0.0", 6969))
sever.listen()
while True:
conn, addr = sever.accept()
print("电话来了",addr)
while True:
data = conn.recv(1024)
if not data: break
print('执行指令',data)
msg,filename = data.decode().split()#接受客户端发过来的命令和文件名
print(filename)
if os.path.isfile(filename):#文件存在
m = hashlib.md5()#(md5改动)生成md5的对象
with open(filename,'rb') as f:
file_size = os.stat(filename).st_size #获取文件大小
conn.send(str(file_size).encode())#发送文件大小
conn.recv(1024)#等待ack
for line in f:
m.update(line)#(md5改动)计算md5值
conn.send(line) #边读边发送给客户端
print('file md5',m.hexdigest())
#conn.recv(1024)#(md5改动)等待客户确认发送md5值
conn.send(m.hexdigest().encode())#((md5改良))生成md5值并发送给客户端
print('send done')
sever.close()
输出
ssh://root@192.168.224.128:22/usr/local/python/bin/python3 -u /root/py/学习/day8/mdclient.py
>>>:get a.txt
get a.txt
server response: b'1'
last receive: 1
1 1
server file md5: 0cc175b9c0f1b6a831c399e269772661
client file md5: 0cc175b9c0f1b6a831c399e269772661
>>>:
socketserver
我们之前的用户都是不支持多并发的,所以我们现在需要一个支持多用户,实现一个并发处理,我们接下来就不能不接触socketserver这个模块。前面讲的socket都是铺垫,后面需要真正使用的是socketserver。
socketserver类型
1、TCPserver
说明:这个是用于TCP协议的,它在客户端和服务器之间提供连续的数据流
class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
2、UDPServer
说明:用于UDP协议的,并非连续的数据包,中间传输可能会丢失。传入的参数和TCPServer是一样的
class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
3、UnixStreamServer和UnixDatagramServer
说明:这个很少用在TCP和UDP类中,但是用正在Unix领域里的sockets;传入的参数和TCPServer是一样的。
class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)
4、五个类实例化过程
创建cocketserver步骤
1、必须自己创建一个请求处理类,并且这个类要继承BaseRequestHandlerclass,并且还有重写父类里的handle()
2、你必须实例化TCPServer,并且传递server ip和你在第一步创建的请求处理类给这个TCPServer
3、接下来调server.handle_request()(只处理一个请求)或者server.serve_forever()(处理多个客户端请求,永远执行)
4、调用server_close()去关闭socket
代码实现:
服务器端:(代码逻辑:先定义一个handler类->实例化TCPServer->serve_forever()实现处理多个客户端请求)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socketserver
class MyTCPhandler(socketserver.BaseRequestHandler):#继承BaseRequestHandler这个基类
def handle(self):
while True:
try:
self.data = self.request.recv(1024)
print('{0} write:'.format(self.client_address[0]))
print(self.data)
self.request.send(self.data.upper())
except ConnectionResetError as e:#抓去异常,这个异常当客户端断开服务端出现断开,这个只有在python3.0才会有
print('error:',e)
break
if __name__ == '__main__':
host,port = '0.0.0.0',9999
server = socketserver.TCPServer((host,port),MyTCPhandler)#每起一个TCPServer都会实例化MyTCPHandler这个类
server.serve_forever()#实现多个连接
server.server_close()#关闭socketserver
注:客户端所有的交互都是在handler里面完成的,每一个请求过来之后,它的请求就会被分配,它的请求的处理规则就是咋子handle里面规定的。服务器收到客户端的数据为空,表明客户端已经断开。
客户端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
client = socket.socket()
client.connect(('0.0.0.0',9999))
while True:
cmd = input('>>>:').strip()
if len(cmd)==0:continue
client.send(cmd.encode())
cmd_res = client.recv(1024)
print(cmd_res.decode('utf-8','ignore'))
client.close()
sockerserver实现多用户并发:
1、多线程
主要在实例化TCPServer时,采用ThreadingTCPServer这种多线程方式。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socketserver
class MyTCPhandler(socketserver.BaseRequestHandler):#继承BaseRequestHandler这个基类
def handle(self):
while True:
try:
self.data = self.request.recv(1024)
print('{0} write:'.format(self.client_address[0]))
print(self.data)
self.request.send(self.data.upper())
except ConnectionResetError as e:#抓去异常,这个异常当客户端断开服务端出现断开,这个只有在python3.0才会有
print('error:',e)
break
if __name__ == '__main__':
host,port = '0.0.0.0',9998
server = socketserver.ThreadingTCPServer((host,port),MyTCPhandler)#改变之处
server.serve_forever()#实现多个连接
server.server_close()#关闭socketserver
ThreadingTCPServer表示服务器每收到客户端一个请求,服务器就会开启一个线程,开启一个线程跟这个链接交互,这个新的线程就是独立的线程,如果你有10个线程,代表可以干10件事。
2、多进程
主要在实例化TCPServer时,采用ForkingTCPServer这种多线程方式,但是这种方式在windows上不好使,需要在Linux上去执行,因为windows和linux处理多进程方式不一样。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socketserver
class MyTCPhandler(socketserver.BaseRequestHandler):#继承BaseRequestHandler这个基类
def handle(self):
while True:
try:
self.data = self.request.recv(1024)
print('{0} write:'.format(self.client_address[0]))
print(self.data)
self.request.send(self.data.upper())
except ConnectionResetError as e:#抓去异常,这个异常当客户端断开服务端出现断开,这个只有在python3.0才会有
print('error:',e)
break
if __name__ == '__main__':
host,port = '0.0.0.0',9998
server = socketserver.ForkingTCPServer((host,port),MyTCPhandler)#采用ForkingTCPServer实现多进程
server.serve_forever()#实现多个连接
server.server_close()#关闭socketserver
这样把socketserver.TCPServer换成socketserver.ThreadingTCPServer,客户端每连进一个来,服务器端就会分配一个新的线程来处理这个客户端的请求。