subprocess

  • 可以通过代码执行操作系统的终端命令, 并返回终端执行命令后的结果
import subprocess

cmd = input('请输入指令; ').strip()

# stdout 返回执行成功结果  stderr 返回保错结果
obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) res = obj.stdout.read() + obj.stderr.read() print(res.decode('gbk'))

粘包问题

问题原因

  • 无法预测需要接收数据的长度, 服务端前一次发送的数据, 客户端无法精确一次性接受完毕, 下一次发送的数据与上一次未发送的数据粘在一起
  • TCP协议: TCP协议是一个流式协议, 会将多次连续发生的数据量小的, 时间间隔短的数据打包一次性发送

解决问题

  • struct模块: 将数据长度压缩成固定长度的一个标记(数据报头)发生给对方, 告诉对方即将发送的数据的真实长度
  • 先定义报头, 发送报头, 再发送真实数据
# server.py
import socket
import subprocess
import struct server = socket.socket() server.bind(
('127.0.0.1', 8888)
) server.listen(5) while True:
conn, addr = server.accept()
print(addr) while True:
try:
# 接收指令
cmd = conn.recv(1024).decode('utf-8') obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 返回终端结果
res = obj.stdout.read() + obj.stderr.read() # 将result长度压缩, 得到报头
headers = struct.pack('i', len(res)) # 将报头发送给客户端
conn.send(headers) # 将结果发送给客户端
conn.send(res) except Exception as e:
print(e)
break conn.close()
# client.py
import socket
import struct client = socket.socket() client.connect(
('127.0.0.1', 8888)
) while True:
cmd = input('请输入指令: ').strip() if cmd == 'q':
break # 向服务端发送指令
client.send(cmd.encode('utf-8')) # 接收报头
headers = client.recv(4) # 解压报头(得到元祖), 获取数据长度
res_len = struct.unpack('i', headers)[0] # 按数据长度接收服务端返回结果
res = client.recv(res_len) print(res.decode('gbk')) client.close()

上传大文件

  • 先发送一个报头, 包含字典长度
  • 再发送该字典, 包含文件名和文件长度信息
  • 最后发送该文件
# server.py
import socket
import struct
import json server = socket.socket() server.bind(
('127.0.0.1', 8888)
) server.listen(5) while True:
conn, addr = server.accept() try:
# 接收字典报头
headers = conn.recv(4) # 解压获取字典长度
dict_len = struct.unpack('i', headers)[0] # 接收字典
bytes_dict = conn.recv(dict_len)
json_dict = bytes_dict.decode('utf-8')
file_info_dict = json.loads(json_dict) print(file_info_dict) # 获取文件名, 文件长度
file_name = file_info_dict.get('file_name')
file_len = file_info_dict.get('file_len') init_len = 0
count = 1
with open(file_name, 'wb') as f: while init_len < file_len:
# 接收视频文件数据
file_data = conn.recv(1024)
# 写入视频文件
f.write(file_data)
print(f'第{count}次接收') init_len += len(file_data)
count += 1 print(f'{file_name}接收完毕!') except Exception as e:
print(e)
break conn.close()
# client.py
import socket
import struct
import json client = socket.socket() client.connect(
('127.0.0.1', 8888)
) # 读取视频文件数据
with open(r'C:\Users\Black\Desktop\client_video.mp4', 'rb') as f:
video_data = f.read() # 视频文件信息字典
file_info_dict = {
'file_name': 'client_video.mp4',
'file_len': len(video_data)
} # 将字典序列化以便获取其长度
json_dict = json.dumps(file_info_dict)
bytes_dict = json_dict.encode('utf-8') # 字典长度报头
headers = struct.pack('i', len(bytes_dict)) # 发送字典报头
client.send(headers) # 发送字典
client.send(bytes_dict) with open(r'C:\Users\Black\Desktop\client_video.mp4', 'rb') as f:
init_len = 0
count = 1
while init_len < len(video_data):
# 一次读取1024字节
file_data = f.read(1024)
# 分多次发送文件数据
client.send(file_data)
print(f'第{count}次发送') init_len += len(file_data)
count += 1 print('文件发送完毕!') client.close()

UDP协议

  • User Datagram Protocol 用户数据报协议

  • 不需要建立双向通道

  • 不会粘包

  • 客户端给服务端发送数据, 不需要等待服务端返回接收成功

  • 面向数据包的不可靠传输层通信协议

# server.py
import socket # 默认为type=socket.SOCK_STREAM, 既TCP协议
server = socket.socket(type=socket.SOCK_DGRAM) server.bind(
('127.0.0.1', 8888)
) # 不需要半连接池和accept建立连接, 直接接收
msg, addr = server.recvfrom(1024) print(msg, addr)
# client.py
import socket # 默认为type=socket.SOCK_STREAM, 既TCP协议
client = socket.socket(type=socket.SOCK_DGRAM) server_ip_port = ('127.0.0.1', 8888) # 直接向指定IP和PORT发送即可
client.sendto(b'hello', server_ip_port)
  • QQ聊天室
# server.py
import socket server = socket.socket(type=socket.SOCK_DGRAM) server.bind(
('127.0.0.1', 8888)
) while True:
recv_msg1, addr1 = server.recvfrom(1024)
# recv_msg2, addr2 = server.recvfrom(1024)
# recv_msg3, addr3 = server.recvfrom(1024) print(recv_msg1.decode('utf-8'))
# print(recv_msg2.decode('utf-8'))
# print(recv_msg3.decode('utf-8')) send_msg = input('输入消息: ') server.sendto(send_msg.encode('utf-8'), addr1)
# server.sendto(send_msg.encode('utf-8'), addr2)
# server.sendto(send_msg.encode('utf-8'), addr3
# client1.py
import socket client = socket.socket(type=socket.SOCK_DGRAM) server_ip_port = ('127.0.0.1', 8888) while True:
send_msg = input('输入消息:') client.sendto(send_msg.encode('utf-8'), server_ip_port) recv_msg, addr = client.recvfrom(1024) print(recv_msg.decode('utf-8'))

SocketServer

  • Python内置模块, 可以简化socket套接字服务端的代码
  • 简化TCP与UDP服务端代码
  • 必须要创建一个类
# server.py
import socketserver # 定义类, 继承socketserver.BaseRequestHandler类
class MyTcpServer(socketserver.BaseRequestHandler): # 重写父类的handle方法
def handle(self):
# 1.接收消息
data = self.request.recv(1024) # conn.recv(1024)
print(data) # 2.发送消息
send_msg = input('from server:')
self.request.send(send_msg.encode('utf-8')) if __name__ == '__main__':
socketserver.TCPServer.allow_reuse_address = True
server = socketserver.TCPServer(
('127.0.0.1', 8888), MyTcpServer
) # 永久执行服务
server.serve_forever()

最新文章

  1. python课程第三周重点记录
  2. BEA-150021 - The admin server failed to authenticate the identity of the user username starting the managed server.
  3. PHP 设计模式 笔记与总结(4)PHP 链式操作的实现
  4. Axis,axis2,Xfire以及cxf对比
  5. (转)mongodb常用命令脚本化-自动化运维
  6. USB相关知识
  7. ThinkPHP3.2 加载过程(二)
  8. apache开源项目--thrift
  9. 2014-08-26 解决HttpContext.Current.Session在ashx文件中出现“未将对象引用设置到对象的实例”的问题
  10. pyqt颜色字符
  11. mysql提示Column count doesn&#39;t match value count at row 1错误
  12. J2EE学习从菜鸟变大鸟之八 企业级项目开发的思考
  13. 在Node.js中使用ffi调用dll
  14. Java8 默认方法
  15. 面试神体验之:get和post的区别
  16. Fiddler 抓包工具怎么使用?怎么在Android手机端的APP抓包
  17. 数据源从druid迁移到HikariCP
  18. 前端路由两种模式:hash、history
  19. svn 提交代码 自动过滤技巧
  20. Asp.Net中使用Newtonsoft.Json转换,读取,写入

热门文章

  1. [LC]876题 Middle of the Linked List (链表的中间结点)(链表)
  2. nyoj 47-过河问题 (贪心)
  3. nyoj 125-盗梦空间 (数学ans += temp * 60 * pow(0.05, cnt))
  4. libwebsocket协议切换状态机
  5. windows下大数据开发环境搭建(1)——Hadoop环境搭建
  6. HashSet源码学习,基于HashMap实现
  7. 快速遍历OpenCV Mat图像数据的多种方法和性能分析 | opencv mat for loop
  8. go中的关键字-go(下)
  9. 基于Pytorch的简单小案例
  10. yum运行报错:/usr/lib64/python2.7/site-packages/pycurl.so: undefined symbol: CRYPTO_num_locks