套接字进阶(python3入门)
一、基于TCP的socket简单通信
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket # 1、买手机 --- 定义socket的方法 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #TCP协议就是流式协议 # 2、插手机卡 --- 绑定IP和端口 server.bind(('127.0.0.1',8080)) # 3、开机(监听) --- 半连接池设定 server.listen(5) # 4、等待电话拨入 --- 一直保持阻塞的状态,直到有客户端连入,才会让代码运行继续下去 conn,addr=server.accept() # print(conn) # print(addr) # 5、接受客户端传来的数据 rec_data = conn.recv(1024) print('接收来自客户端的数据:',rec_data) # 6、回复客户端信息 rep_data = conn.send(rec_data.upper()) # 7、服务端关闭连接 conn.close()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket # 1、买手机 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 2、拨号码给服务端 --- 连接服务器的ip和指定端口(建立连接) client.connect(('127.0.0.1',8080)) # 3、发送数据 sen_data = client.send(b'hello') # 4、接收服务端的回应 rec_data = client.recv(1024) print('接收来自服务端的回复:',rec_data) # 5、关闭此次通话 --- 关闭本次连接通道 client.close()
二、基于TCP的socket简单通信升级版本(通信循环+连接循环)
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket # 1、买手机 --- 定义socket的方法 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #TCP协议就是流式协议 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #为了防止端口被占用,在调试阶段可以反复 复用同一端口 # 2、插手机卡 --- 绑定IP和端口 server.bind(('127.0.0.1',8080)) # 3、开机(监听) --- 半连接池设定 server.listen(5) while True: # 4、等待电话拨入 --- 一直保持阻塞的状态,直到有客户端连入,才会让代码运行继续下去 conn,addr=server.accept() print('本次连接对对象为:',conn) print('本次连接的客户端信息为:',addr) while True: try: print('ssss') # 5、接受客户端传来的数据 rec_data = conn.recv(1024) if len(rec_data) == 0:break print('接收来自客户端的数据:',rec_data) # 6、回复客户端信息 rep_data = conn.send(rec_data.upper()) except Exception as e: break # 7、服务端关闭连接 conn.close()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket # 1、买手机 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 2、拨号码给服务端 --- 连接服务器的ip和指定端口(建立连接) client.connect(('127.0.0.1',8080)) while True: msg = input('>>>>:').strip() if len(msg) == 0:continue # 3、发送数据 sen_data = client.send(bytes(msg,encoding='utf-8')) # 4、接收服务端的回应 rec_data = client.recv(1024) print('接收来自服务端的回复:',rec_data) # 5、关闭此次通话 --- 关闭本次连接通道 client.close()
三、服务端subprocess处理结果返回客户端
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket import subprocess #买手机 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #为了防止端口被占用,在调试阶段可以反复 复用同一端口 #sim卡 server.bind(('127.0.0.1',8080)) #开机设定半连接池 server.listen(5) while True: #等待电话拨入 conn,addr = server.accept() while True: #接收客户端发来的数据 rdata = conn.recv(1024) if len(rdata) == 0:break obj = subprocess.Popen(rdata.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = obj.stdout.read() stderror = obj.stderr.read() print(stdout.decode('utf-8')) print(stderror.decode('utf-8')) total_data = stdout+stderror # print('收到来自客户端发来的消息:',rdata.decode('utf-8')) #返回数据给客户端 sdata = conn.send(total_data) conn.close()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket #买手机 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #与服务端建立连接 client.connect(('127.0.0.1',8080)) while True: msg = input('>>>>:').strip() if len(msg) == 0:continue #发送消息到服务端 client.send(bytes(msg,encoding='utf-8')) #接收服务端的数据 rdata = client.recv(1024) print('收到来自服务端的回复:') print(rdata.decode('utf-8')) client.close()
四、处理粘包问题
#! /usr/bin/env python # -*- coding: utf-8 -*- ''' 1.什么是粘包 数据报一个个连续不间断的发回客户端,产生的一种现象。 2.为什么会有粘包 所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的(这是流式协议的锅) 3.如何处理粘包 使用两个变量,一个是接收的total_data,一个是服务端执行结果的长度 这样客户端就可以通过服务端传回的结果长度,来判断何时可以完成数据接收 简单来说: 先将执行结果的长度 打包成固定的一个长度的包 然后将这个定长的包优先发发送到客户端 最后将执行结果推送至客户端 ''' import socket import subprocess import struct #买手机 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #为了防止端口被占用,在调试阶段可以反复 复用同一端口 #sim卡 server.bind(('127.0.0.1',8080)) #开机设定半连接池 server.listen(5) while True: #等待电话拨入 conn,addr = server.accept() while True: #接收客户端发来的数据 rdata = conn.recv(1024) if len(rdata) == 0:break obj = subprocess.Popen(rdata.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = obj.stdout.read() stderror = obj.stderr.read() print(stdout.decode('utf-8')) print(stderror.decode('utf-8')) #将stdout+stderr的长度进行打包 total_size = len(stdout) + len(stderror) total_size = struct.pack('i',total_size) conn.send(total_size) total_data = stdout+stderror # print('收到来自客户端发来的消息:',rdata.decode('utf-8')) #返回数据给客户端 sdata = conn.send(total_data) conn.close()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket import struct #买手机 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #与服务端建立连接 client.connect(('127.0.0.1',8080)) while True: msg = input('>>>>:').strip() if len(msg) == 0:continue #发送消息到服务端 client.send(bytes(msg,encoding='utf-8')) #优先接收服务端处理结果的长度信息 total_size = client.recv(4) total_size = struct.unpack('i',total_size)[0] # print(total_size) rdata = b'' rsize = 0 while rsize < total_size: data = client.recv(1024) rdata += data rsize += len(data) # #接收服务端的数据 print('收到来自服务端的回复:') print(rdata.decode('utf-8')) client.close()
五、处理粘包问题终极版
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket import subprocess import json import struct server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #为了防止端口被占用,在调试阶段可以反复 复用同一端口 server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn,addr = server.accept() while True: try: rdata = conn.recv(1024) if len(rdata) == 0:break print('来自客户端的消息:') print(rdata.decode('utf-8')) obj = subprocess.Popen( rdata.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout = obj.stdout.read() stderror = obj.stderr.read() # print(stdout,stdout.decode('utf-8')) total_size = len(stdout) + len(stderror) # total_size = struct.pack('i',total_size) header_dic = { 'file_name':'test', 'total_size':total_size, 'hash':'aaabbbcccddd' } header_str = json.dumps(header_dic) header_bytes = header_str.encode('utf-8') header_size = struct.pack('i',len(header_str)) sdata = stdout + stderror # print(sdata) conn.send(header_size) # 先将字典序列化为字符串,计算字符串的长度,将该长度压缩成4个字节发送给客户端 conn.send(header_bytes) # 然后将字典编码为bytes发送给客户端 conn.send(sdata) # 最终将执行结果发送给客户端 except Exception as e: print(e) break conn.close()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket import json import struct client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: msg = input('>>>>:') if len(msg) == 0:continue client.send(bytes(msg,encoding='utf-8')) header_bytes = client.recv(4) #仅接收服务端打包先发来的前4个字节的数据 header_size = struct.unpack('i',header_bytes)[0] #将该4个字节数据进行解压,或者字典序列化成字符串的长度 # header_dic = json.loads(header_bytes) header_dic_bytes = client.recv(header_size) # 随即接收上述解压后的字节长度,该出长度中的数据为数据头字典数据 header_dic_str = header_dic_bytes.decode('utf-8') # 将该数据进行解码,得到json格式的字符串 header_dic = json.loads(header_dic_str) # 将json格式的字符串反序列化为字典 # print(header_dic,type(header_dic)) rdata = b'' rsize = 0 while rsize < header_dic['total_size']: data = client.recv(1024) rdata += data rsize += len(data) # rdata = client.recv(1024) print('来自服务端的回应:') print(rdata.decode('utf-8')) client.close()
六、基于UDP协议的客户端与服务端简单通信
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # udp数据报协议 server.bind(('127.0.0.1',8080)) while True: rdata,addr = server.recvfrom(1024) print(rdata.decode('utf-8')) print(addr) sdata = server.sendto(rdata.upper(),addr) server.close()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) while True: msg = input('>>>>>:') client.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) #发送数据所使用的函数与tcp不同,请注意 rdata,server_addr = client.recvfrom(1024) #接收数据使用的函数与tcp不同,请注意! print(rdata.decode('utf-8')) print(server_addr) client.close()
七、socketserver实现简单并发编程
#! /usr/bin/env python # -*- coding: utf-8 -*- import socketserver class MyHandler(socketserver.BaseRequestHandler): def handle(self): while True: try: rdata = self.request.recv(1024) if len(rdata) == 0:break self.request.send(rdata.upper()) print('从客户端接收到的数据:',rdata.decode('utf-8')) print('客户端的地址为:',self.client_address) # print(self.__dict__) except Exception as e: print(e) break if __name__ == '__main__': # 多开了一个线程,来服务客户端(线程:可以理解为多加了一个服务员) # socketserver.ThreadingTCPServer(server_address=,RequestHandlerClass=,bind_and_activate=) obj = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyHandler,bind_and_activate=True) # obj.allow_reuse_address = True obj.serve_forever()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: msg = input('>>>>:') if len(msg) == 0:continue client.send(bytes(msg,encoding='utf-8')) rdata = client.recv(1024) print(rdata.decode('utf-8')) client.close()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: msg = input('>>>>:') if len(msg) == 0:continue client.send(bytes(msg,encoding='utf-8')) rdata = client.recv(1024) print(rdata.decode('utf-8')) client.close()
#! /usr/bin/env python # -*- coding: utf-8 -*- import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: msg = input('>>>>:') if len(msg) == 0:continue client.send(bytes(msg,encoding='utf-8')) rdata = client.recv(1024) print(rdata.decode('utf-8')) client.close()