socketsoerver类的五大类型之间的联系:
日常主要用到的是以下这两个类型,但是,你会发现这两个类型,并没法实现我们要的多客户端连接,只等前一个连接结束,后一个连接才可以开始。
socketserver.TCPServer:是用于TCP连接
socketserver.UDPServer:是用于UDP连接
要想实现多客户端连接,则需要用以下两个类型
socketserver.ThreadingTCPServer:支持并发连接,即每收到一个连接请求,都会派出一个小弟(也就是创建一个线程)去连接。
ocketserver.ThreadingUDPServer:也是通过线程来实现高并发的
socketserver类的基本用法步骤:(以TCP连接为例子)
import socketserver
import subprocess
#第一步:创建一个类,该类需要继承socketserver的基础类BaseRequestHandler,
#同时,需要重写该基础类的handle()方法
class myTCPHandler(socketserver.BaseRequestHandler):
#重写handle方法
def handle(self):
#这里是实现接收跟发送的代码
pass
if __name__=='__main__':
host,port='localhost',9999
#第二步:创建一个socketserver类中其中一种类型的实例
#同时,把元组(IP,port),以及第一步创建的类,传给这个实例
server=socketserver.ThreadingTCPServer((host,port),myTCPHandler)
#第三步:调用server_forever()/handle_request()方法来处理请求
#多连接请求
server.serve_forever()
#server_forever()等价于socket类中以下这部分代码
#while True:
# con, addr = server_sock.accept()
#单链接请求:
handle_request()
#等价于socket类以下这句代码
#con, addr = server_sock.accept()
完整例子如下:(模拟远程执行cmd命令)
#服务端
# -*-coding:utf-8 -*-
import socketserver
import subprocess
class myTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
self.data=self.request.recv(1024).strip()
data=subprocess.Popen(self.data.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
stdout=data.stdout.read()
print('----------------')
print('输出',stdout)
# stdin=data.stdin.read()
stderr=data.stderr.read()
print('异常输出',stderr)
if len(stdout)==0:
l=len(stderr)
self.request.sendall(str(l).encode())
self.request.sendall(stderr)
else:
l = len(stderr)
self.request.sendall(str(l).encode())
self.request.sendall(stdout)
if __name__=='__main__':
host,port='localhost',9999
server=socketserver.ThreadingTCPServer((host,port),myTCPHandler)
server.serve_forever()
#客户端
# -*-coding:utf-8 -*-
import socket
c=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port=('localhost',9999)
c.connect(ip_port)
while True:
cmd=input('cmd>>:')
c.send(cmd.encode())
data_len=c.recv(1024).decode('utf-8')
print('客户端发送过来的数据长度是:'+data_len)
i=int(data_len)/1024
print(i)
data=b''
while i+1>=1:
data+=c.recv(1024)
i-=1
# print(n,type(n))
# data=c.recv(1024)
print(data.decode('gbk'))
UDP跟TCP使用socketserver的区别;
UDP:
接收数据: data= self.request[0]
获取套接字对象 udp_s = self.request[1]
获取IP_port: add = self.client_address
TCP:
data=self.request.recv(1024)
直接用self.request就可以发数据,收数据
具体例子如下:
# -*-coding:utf-8 -*-
import socketserver
import subprocess
class UDPhandle(socketserver.BaseRequestHandler):
def handle(self):
while True:
cmd = self.request[0]
udp_s = self.request[1]
add = self.client_address
cmd_data = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
stderr = cmd_data.stderr.read()
stdout = cmd_data.stdout.read()
if not stderr:
d = str(len(stdout))
udp_s.sendto(d.encode(), add)
udp_s.sendto(stdout, add)
else:
d = str(len(stderr))
udp_s.sendto(d.encode(), add)
udp_s.sendto(stderr, add)
if __name__=='__main__':
udp_s=socketserver.ThreadingUDPServer(('localhost',1111),UDPhandle)
udp_s.serve_forever()
客户端
# -*-coding:utf-8 -*-
import socket
udp_c=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
ip_port=('localhost',1111)
while True:
msg=input('>>:').strip()
if not msg:
continue
udp_c.sendto(msg.encode(),ip_port)
size=int(udp_c.recv(1024))
print(size)
backPmsg,addr=udp_c.recvfrom(size)
print(backPmsg.decode('gbk'))