Socket
一、Socket
1.UDP协议
数据报协议
无需建立双向通道,数据传输是不安全
将内存中的数据直接发送出去,不会做保留
早期的qq
ps:TCP协议类似于打电话,UDP协议类似于发短信
2.TCP特点:
会将数据量比较小的并且时间间隔比较短的数据一次性打包发送给对方
3.OSI协议补充

4.解决端口占用问题
from socket import SOL_SOCKET,SO_REUSEADDR sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
5.socket通信简单版本
服务端
import socket server = socket.socket() # 买手机 不传参数默认用的就是TCP协议 server.bind(('127.0.0.1',8080)) # bind((host,port)) 插电话卡 绑定ip和端口 server.listen(5) # 开机 半连接池 conn, addr = server.accept() # 接听电话 等着别人给你打电话 阻塞 data = conn.recv(1024) # 听别人说话 接收1024个字节数据 阻塞 print(data) conn.send(b'hello baby~') # 给别人回话 conn.close() # 挂电话 server.close() # 关机
客户端
import socket client = socket.socket() # 拿电话 client.connect(('127.0.0.1',8080)) # 拨号 写的是对方的ip和port client.send(b'hello world!') # 对别人说话 data = client.recv(1024) # 听别人说话 print(data) client.close() # 挂电话
总结:
127.0.0.1本机回还地址
只能自己识别自己,其他人无法访问
send与recv对应
不要出现两边都是相同的情况
recv是跟内存要数据(至于数据的来源,你无需考虑)
6.半连接池的理解
7.连接循环+通信循环
服务端
import socket """ 服务端 固定的ip和port 24小时不间断提供服务 """ server = socket.socket() # 生成一个对象 server.bind(('127.0.0.1',8080)) # 绑定ip和port server.listen(5) # 半连接池 while True: conn, addr = server.accept() # 等到别人来 conn就类似于是双向通道 print(addr) # ('127.0.0.1', 51323) 客户端的地址 while True: try: data = conn.recv(1024) print(data) # b'' 针对mac与linux 客户端异常退出之后 服务端不会报错 只会一直收b'' if len(data) == 0:break conn.send(data.upper()) except ConnectionResetError as e: print(e) break conn.close()
客户端
import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while True: msg = input('>>>:').encode('utf-8') if len(msg) == 0:continue client.send(msg) data = client.recv(1024) print(data)
8.TCP粘包问题
服务端
import socket server = socket.socket() # 买手机 不传参数默认用的就是TCP协议 server.bind(('127.0.0.1',8080)) # bind((host,port)) 插电话卡 绑定ip和端口 server.listen(5) # 开机 半连接池 conn, addr = server.accept() # 接听电话 等着别人给你打电话 阻塞 data = conn.recv(5) # 听别人说话 接收1024个字节数据 阻塞 print(data) data = conn.recv(5) # 听别人说话 接收1024个字节数据 阻塞 print(data) data = conn.recv(4) # 听别人说话 接收1024个字节数据 阻塞 print(data)
客户端
import socket client = socket.socket() # 拿电话 client.connect(('127.0.0.1',8080)) # 拨号 写的是对方的ip和port client.send(b'hello') client.send(b'world') client.send(b'baby')
如何将数据打包成固定的包?
运用struct模块
import struct res = 'ssssssssssssssssssssssss' # 当原始数据特别大时,i模式打包不了,需要更换其他模式 res1 = struct.pack('i',len(res)) print(len(res1)) # 打包后的数据长度为4 res2 = struct.unpack('i',res1)[0] print(res2) # 解包之后的真实数据长度
当数据量特别大的情况下该如何解决
import struct # 当原始数据特别大的时候 i模式打包不了 需要更换模式? # 如果遇到数据量特别大的情况 该如何解决? d = { 'name':'jason', 'file_size':3455435435345354524534532456546546565466564366463654543453454353455, 'info':'为大家的骄傲' } import json json_d = json.dumps(d) print(len(json_d)) res1 = struct.pack('i',len(json_d)) print(len(res1)) res2 = struct.unpack('i',res1)[0] print('解包之后的',res2)
9.解决粘包问题
(1)发送数据直接先告诉对方数据量的大小
(2)利用struct模块定制我们自己的消息传输协议
服务端
(1)先制作一个发送给客户端的字典
(2)制作字典的报头
(3)发送字典的报头
(4)发送字典
(5)再发真实数据
客户端
(1)先接受字典的报头
(2)解析拿到字典的数据长度
(3)接收字典
(4)从字典中获取真实数据的长度
(5)接收真实数据
import socket import subprocess import struct import json server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn, addr = server.accept() while True: try: cmd = conn.recv(1024) if len(cmd) == 0:break cmd = cmd.decode('utf-8') obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) res = obj.stdout.read() + obj.stderr.read() d = {'name':'jason','file_size':len(res),'info':'asdhjkshasdad'} json_d = json.dumps(d) # 1.先制作一个字典的报头 header = struct.pack('i',len(json_d)) # 2.发送字典报头 conn.send(header) # 3.发送字典 conn.send(json_d.encode('utf-8')) # 4.再发真实数据 conn.send(res) # conn.send(obj.stdout.read()) # conn.send(obj.stderr.read()) except ConnectionResetError: break conn.close()
客户端
import socket import struct import json client = socket.socket() client.connect(('127.0.0.1',8080)) while True: msg = input('>>>:').encode('utf-8') if len(msg) == 0:continue client.send(msg) # 1.先接受字典报头 header_dict = client.recv(4) # 2.解析报头 获取字典的长度 dict_size = struct.unpack('i',header_dict)[0] # 解包的时候一定要加上索引0 # 3.接收字典数据 dict_bytes = client.recv(dict_size) dict_json = json.loads(dict_bytes.decode('utf-8')) # 4.从字典中获取信息 print(dict_json) recv_size = 0 real_data = b'' while recv_size < dict_json.get('file_size'): # real_size = 102400 data = client.recv(1024) real_data += data recv_size += len(data) print(real_data.decode('gbk'))
10.关于subproccess应用
import subprocess cmd = input('cmd>>>:') obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) print(obj.stdout.read().decode('gbk')) # 正确命令返回的结果 print(obj.stderr.read().decode('gbk')) # 错误的命令返回的结果 # subprocess获取到的数据 拿完就没有了 不能重复的拿 print(obj.stdout.read().decode('gbk')) # 正确命令返回的结果 print(obj.stderr.read().decode('gbk')) # 错误的命令返回的结果

浙公网安备 33010602011771号