1、socker层 (在程序中就是一个模块功能能够直接导入使用)python
Socker 是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口,其实就i是一个门面模式,把复杂的协议放在socker后面。git
IP地址: 127.0.0.1是本机回还地址,只能本身识别本身,其余人没法访问,用于python代码客户端和服务端的测试shell
2、 套接字(socker)的发展史json
1:基于文件类型的套接字家族:AF_UNIX(一切皆文件)网络
2:基于网络类型的套接字家族:AF_INET(被用于ipv6)socket
3、tcp协议和udp协议tcp
TCP:可靠的面向链接的协议(如:打电话),传输效率低于全双工通讯ide
UDP:不可靠的、无链接的服务,传输效率高,一对一,一对多函数
TCP和TCP间的通讯测试
4、套接字(socker)的使用
client(客户端)关键字:connect send recv
server(服务端)关键字:bind listen accept recv send conn.slose()
TCP协议是基于链接的,必须先启动服务端,而后在启动客户端去链接服务端:
server:服务端
import socket """" 实现服务端24小时不间断的服务功能,固定的IP和port """ server = socket.socket() # 生成一个对象 server.bind(('127.0.0.1',8080)) # 绑定ip和port server.listen(5) # 半链接池 """ 用两层循环 实现客户端与服务端之间的循环交互式 """ while True: conn,addr = server.accept() # 循环接收用户端的请求 print(addr) while True: try:# 解决报错抛出的异常处理(位置,类型,) data = conn.recv(1024) print(data) if len(data) == 0 : break # 针对mac和 Linux 客户端异常退出以后 conn.send(data.upper()) # 返转成大写 except ConnectionRefusedError as e: # 提示的报错信息 print(e) break conn.close()
client:客户端
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)
send(发出)与recv(接收)对应关系,不能出现两边都相同的状况
recv 是跟内存要数据的,
TCP的特色:
会将数据量比较小的而且时间间隔比较短的数据
一次性打包发送给对方
利用socker模块,用代码实现了服务端与客户端的实际交互状况,IP地址和pore端口地址必须彻底匹配,其中注意一些概念 如 server.listen(5) # 半链接池 指的是规定客户端访问的量,报错的异常处理
一个做为接收端,一个做为反馈请求端,所用的参数也不同
5、黏包
黏包:指的是当客户端同时请求所传输的内容过大,过长是,服务端反馈的结果可能只有其中的一部分,显示不全,在执行其余命令的时候又接受收到了以前执行的另一部分的结果。
补充的subprocess子进程模块
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')) # 错误的命令返回的结果
只能单次获取请求的数据,取完就没了, 不能重复的取
该模块能够在python解释器里,实现终端的请求命令行执行并打印结果:
它的功能以及经常使用的操做
# subprocess模块 # 1.用户经过网络链接上了你的这台电脑 # 2.用户输入相应的命令 基于网络发送给了你这台电脑上某个程序 # 3.获取用户命令 里面subprocess执行该用户命令 # 4.将执行结果再基于网络发送给用户 # 这样就实现 用户远程操做你这台电脑的操做 # ''
该模块能够把一个类型,如数字,转成固定长度的bytes
struct.pack:打包
struct.unpack解包
有“i” ’q‘等模式,是处理数据大小的等级
dict_size = struct.unpack('i',header_dict)[0] # 解包的时候必定要加上索引0
服务端:结合json模块 dumps序列化成一个字典,制做一个报头
客户端:用loads把字典反序列化成字符串出来,读取报头内容
当有黏包现象存在时如何解决?(即数据过大过长时)
服务端client:
1:先制做一个发送给客户端色字典
2:制做字典的报头
3:发送字典的报头
4:再发真实的数据
客户端srever:
1.先接受字典的报头
2.解析拿到字典的数据长度
3.接受字典
4.从字典中获取真实数据的长度
5.接受真实数据
用字典打包好报头,获取固定的长度后在传输
内置函数构造:
简单黏包问题的存在,接收的数据和传出去的不同
client 客户端
import socket client = socket.socket() # 拿电话 client.connect(('127.0.0.1',8080)) # 拨号 写的是对方的ip和port client.send(b'hello') client.send(b'baby')
server:服务端
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)
注意:只有TCP有粘包现象,UDP永远不会粘包
实现解决黏包的问题?
客户端:client
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')) """ 1.如何将对方发送的数据收干净
服务端:server
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()
文件的上传和下载
(重点掌握,也是基于tcp协议的一个粘包问题,利用打包和解包)
import socket import json import os import struct client= socket.socket() client.connect(('127.0.0.1',8080)) while True: MOVIE_DIR = r'E:\python脱产10期视频\day29\视频' movie_list= os.listdir(MOVIE_DIR) for i,movie in enumerate(movie_list,1): # 枚举列出全部数据 print(i,movie) # 用户选择 choice=input("请选择你要下载的视频>>:") if choice.isdigit(): choice = int(choice)-1 if choice in range(0,len(movie_list)): path = movie_list[choice] file_path = os.path.join(MOVIE_DIR,path) file_size = os.path.getsize(file_path) res_d={ 'file_name':"精彩视频要你好看.MP4", 'file_size':file_size, 'msg':"作个年少有为的青年" } json_d = json.dumps(res_d) json_bytes = json_d.encode('utf-8') header = struct.pack('i',len(json_bytes)) client.send(header) client.send(json_bytes) with open (file_path,'rb') as f: for line in f : client.send(line) else: print("not in range") else: print("must be a number") """ if else 的使用 先把正确逻辑的代码写好,后面再考虑搭配来写else的其余状况 """
import json import socket import struct server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn,addr = server.accept() while True: try: header_len = conn.recv(4) # 解析字典报头 header_len=struct.unpack('i',header_len)[0] # 再接收字典数据 header_dic = conn.recv(header_len) real_dic = json.loads(header_dic.decode('utf-8')) total_size = real_dic.get('file_size') recv_size = 0 with open (real_dic.get('file_name'),'wb') as f: while recv_size < total_size: data = conn.recv(1024) f.write(data) recv_size+= len(data) print("上传成功!") except ConnectionRefusedError as e: print(e) break conn.close()
简易版本的QQ实现:
QQ服务端:
import socket server = socket.socket(type=socket.SOCK_DGRAM) server.bind(('127.0.0.1',8080)) while True: data,adder = server.recvfrom(1024) msg= input(">>>>:") server.sendto(msg.encode('utf-8'),adder)
QQ客户端:
import socket client = socket.socket(type=socket.SOCK_DGRAM) server_address = ('127.0.0.1',8080) while True: msg = input('>>>:') msg = '来自客户端1的消息:%s'%msg client.sendto(msg.encode('utf-8'),server_address) data, server_addr = client.recvfrom(1024) print(data.decode('utf-8'))