标签:except 缓冲区 函数 block 传输 封装 bre 路径 存在
import socket
socket.socket(socket_family,socket_type,protocal=0)
socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。
# 获取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpSock = socket.socket() # 括号里可以不写 默认
# 获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。
例如tcpSock = socket(AF_INET, SOCK_STREAM)
##============服务端套接字函数
s.bind() # 绑定(主机,端口号)到套接字
s.listen() # 开始TCP监听
s.accept() # 被动接受TCP客户的连接,(阻塞式)等待连接的到来
##============客户端套接字函数
s.connect() # 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
##============公共用途的套接字函数
s.recv() # 接收TCP数据
s.send() # 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() # 关闭套接字
面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间
面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件
# server端
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 创建socket 对象
phone.bind(('127.0.0.1',8080)) # 8000 ~ 65535 绑定ip地址和端口
phone.listen(5) # TCP 开始监听
# conn相当于管道
conn, client_addr = phone.accept() # 被动接受TCP客户的连接,(阻塞式)等待连接的到来
print(conn, client_addr, sep='\n') # 打印通道 和 客户端的地址
from_client_data = conn.recv(1024) # 每次 接收 客户端内容 的 最大限制 1024 bytes
print(from_client_data.decode('utf-8'))
conn.send(from_client_data.upper()) # 向客户端发送 信息
conn.close() # 挂电话
phone.close() # 关闭套接字
# client
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话
phone.connect(('127.0.0.1',8080)) # 与客户端建立连接, 拨号
phone.send('hello'.encode('utf-8'))
from_server_data = phone.recv(1024)
print(from_server_data.decode('utf-8'))
phone.close() # 挂电话
# server
import socket
photo = socket.socket()
photo.bind(('127.0.0.1',8080))
phone.listen(5)
conn, client_addr = phone.accept()
print(conn, client_addr, sep='\n')
while 1: # 循环收发消息
try:
from_client_data = conn.recv(1024)
print(from_client_data.decode('utf-8'))
conn.send(from_client_data + b'SB')
except ConnectionResetError:
break
conn.close()
phone.close()
# client
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话
phone.connect(('127.0.0.1',8080)) # 与客户端建立连接, 拨号
while 1: # 循环收发消息
client_data = input('>>>')
phone.send(client_data.encode('utf-8'))
from_server_data = phone.recv(1024)
print(from_server_data.decode('utf-8'))
phone.close() # 挂电话
***
# server
import socket
phone = socket.socket()
phone.bind(('127.0.0.1', 8080))
phone.listen(5)
while 1: # 循环连接客户端
conn, client_addr = phone.accept()
print(conn,client_addr)
while 1:
try:
from_client_data = conn.recv(1024)
print(from_client_data.decode('utf-8'))
conn.send(from_client_data + b'SB')
except ConnectionResetError:
break
conn.close()
phone.close()
# client
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话
phone.connect(('127.0.0.1',8080)) # 与客户端建立连接, 拨号
while 1:
client_data = input('>>>')
phone.send(client_data.encode('utf-8'))
from_server_data = phone.recv(1024)
print(from_server_data.decode('utf-8'))
phone.close() # 挂电话
# server
import socket
import subprocess
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8080))
phone.listen(5)
while 1 : # 循环连接客户端
conn, client_addr = phone.accept()
print(client_addr)
while 1:
try:
cmd = conn.recv(1024)
ret = subprocess.Popen(cmd.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
correct_msg = ret.stdout.read()
error_msg = ret.stderr.read()
conn.send(correct_msg + error_msg)
except ConnectionResetError:
break
conn.close()
phone.close()
# client
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话
phone.connect(('127.0.0.1',8080)) # 与客户端建立连接, 拨号
while 1:
cmd = input('>>>')
phone.send(cmd.encode('utf-8'))
from_server_data = phone.recv(1024)
print(from_server_data.decode('gbk'))
phone.close() # 挂电话
''' 服务端 发出 客户端 接收
第一次dir 数据418 < 1024 数据全部发出 数据全部接收
第二次ipconifg 数据1517 > 1024 数据只发送1024个字节 数据只接收1024个字节
第三次 dir 数据418 < 1024 数据是谁? 数据接收493个字节 '''
基于tcp协议的socket
提高上传下载的效率 , 保持稳定性 , 释放cpu ,减少与磁盘的交互
错误示例
思路
分析一下功能
send的多次, recv一次 (不是一发一收制)
解决粘包现象的思路分析
当我第二次给服务器发送命令之前 , 我应该 循环 recv 直至将所有的数据全部取完
问题 :
如何限制循环次数?
当你发送的总bytes个数,与接收的总bytes个数相等时 , 循环结束
如何获取发送的总bytes 个数 : len() ---->3400字节 int
所以 :
服务端
send(总个数)
send(总数据)
总个数是什么类型? int() 3400 , send 需要发送bytes类型
send(总个数)
? 将int 转外成 bytes 即可 b‘ 3400
? 方案一:
str(3400) --->‘‘3400"---->b‘3400
解决统一头部问题
无论总字节个数是多少?
将不固定的int类型, 转化成固定长度的bytes类型 , 方便获取头部信息
s1 = "alexsb"
b1 = s1.encode("utf-8")
print(b1)
print(len(b1)) # 6 len 可以计算 utf-8 的 字节数
import struct
# 将一个数字转化成等长度的bytes类型。
ret = struct.pack('i', 183346)
print(ret, type(ret), len(ret)) # b'2\xcc\x02\x00' <class 'bytes'> 4
# 通过unpack反解回来
ret1 = struct.unpack('i',ret)
print(ret1,type(ret), len(ret)) # (183346,) <class 'bytes'> 4
print(ret1[0])
# 但是通过struct 处理不能处理太大
#
ret2 = struct.pack('i', 1234567890) # 极限长度 再长就报错
print(ret2, type(ret2), len(ret2)) # b'\xd2\x02\x96I' <class 'bytes'> 4
# 报错长度
ret2 = struct.pack('i', 12345678900) # 极限长度 再长就报错
print(ret2, type(ret2), len(ret2)) # 报错
# server 模拟远程控制主机cmd命令
import socket
import struct
import subprocess
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while 1:
while 1:
conn, addr = server.accept()
try:
cmd = conn.recv(1024)
obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
ret = obj.stdout.read() + obj.stderr.read()
print(f'准备发送{len(ret)}个字节')
ret_len = struct.pack('i',len(ret)) # 包装固定4个字节 报头
conn.send(ret_len) # 发送报头
conn.send(ret) # 发送真实数据
except Exception:
break
conn.close()
server.close()
# 但是low版本有问题:
# 1,报头不只有总数据大小,而是还应该有MD5数据,文件名等等一些数据。
# 2,通过struct模块直接数据处理,不能处理太大。
# client
import socket
import struct
client = socket.socket()
client.connect(('127.0.0.1', 8080))
while 1:
cmd = input(">>>").strip()
client.send(cmd.encode('utf-8')) # 发送命令
from_server_head = client.recv(4) # 接收server包装过的固定报头
from_server_head_int = struct.unpack('i',from_server_head)[0] # 反序列报头是 元组 , +[0]才是报头
# 解析报头
print(f'准备接收{from_server_head_int}个字节')
from_server_data = b''
while from_server_head_int > len(from_server_data):
from_server_data += client.recv(1024) # 接收真实数据
print(from_server_data.decode('gbk'))
print(f'客户端接收了{len(from_server_data)}个字节')
client.close()
整个流程的大致解释:
我们可以把 ,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后 json序列化,然后用 struck
将序列化后的数据长度打包成
我们在网络上传输的所有数据 都叫做 数据包 ,数据包里的所有数据都叫做 报文,报文里面不止有你的数据,还有ip地址、mac地址、端口号等等,其实所有的报文都有报头,这个报头是协议规定的,看一下
发送时:
接收时:
# server
import socket
import subprocess
import struct
import json
server = socket.socket()
server.bind(('127.0.0.1', 8088))
server.listen(5)
while 1:
conn,addr = server.accept()
print('start')
try:
cmd = conn.recv(1024)
print(f'{cmd.decode("utf-8")}')
obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
ret = obj.stdout.read() + obj.stderr.read()
ret = ret.decode('gbk').encode('utf-8')
# 1.制作 字典式 报头
head_dict = {'md5':'jrwiwfwr432knd324n23n2j131k',
'file_name':'朝花夕拾',
'file_size':len(ret)}
# 2.将报头字典转化成json字符串
head_dict_json = json.dumps(head_dict)
# 3. 将json字符串 转化成bytes
head_dict_json_bytes = head_dict_json.encode('utf-8')
# 4. 获取报头的长度
head_len = len(head_dict_json_bytes)
# 5.将长度转化成固定的4个字节
head_len_bytes = struct.pack('i',head_len)
# 6. 发送固定的4个字节报头
conn.send(head_len_bytes)
# 7. 发送字典
conn.send(head_dict_json_bytes)
# 8. 发送原数据
conn.send(ret)
except ConnectionResetError:
break
conn.close()
server.close()
import socket
import struct
import json
client = socket.socket()
client.connect(('127.0.0.1', 8088))
# 发消息
while 1:
cmd = input('>>>')
client.send(cmd.encode('utf-8'))
# 1. 接收报头
head_4 = client.recv(4)
# 2. 将报头反解回int类型
head_size = struct.unpack('i',head_4)[0] # 接收 并 解析4个字节的报头
ret = json.loads(client.recv(head_size).decode('utf-8')) # 接收 并 转化 固定长度的字典
print(ret) # 字典
recv_date = b''
while len(recv_date) < head_size:
recv_date += client.recv(1024)
print(recv_date.decode("utf-8"))
client.close()
标签:except 缓冲区 函数 block 传输 封装 bre 路径 存在
原文地址:https://www.cnblogs.com/fanxss/p/11219212.html