Python3 网络基础基础2
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()
Python3 网络基础基础2的更多相关文章
- Python3 网络编程基础1
目录 开发架构 C/S架构 B/S架构 OSI模型 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 TCP协议 socket 开发架构 C/S架构 client 和 server, 既客户 ...
- C#网络编程基础知识
C#网络编程基础知识一 1.IPAddress类 用于表示一个IP地址.IPAddress默认构造函数 public IPAddress(long address);一般不用 其中Parse()方法最 ...
- iOS开发网络篇—网络编程基础
iOS开发网络篇—网络编程基础 一.为什么要学习网络编程 1.简单说明 在移动互联网时代,移动应用的特征有: (1)几乎所有应用都需要用到网络,比如QQ.微博.网易新闻.优酷.百度地图 (2)只有通过 ...
- Python3学习(1)-基础篇
Python3学习(1)-基础篇 Python3学习(2)-中级篇 Python3学习(3)-高级篇 安装(MAC) 直接运行: brew install python3 输入:python3 --v ...
- Android 网络编程基础之简单聊天程序
前一篇讲了Android的网络编程基础,今天写了一个简单的聊天程序分享一下 首先是服务端代码: package com.jiao.socketdemo; import java.io.Buffered ...
- 服务器编程入门(4)Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字( ...
- Java网络编程基础(Netty预备知识)
今天在家休息,闲来无事,写篇博客,陶冶下情操~~~ =================我是分割线================ 最近在重新学习Java网络编程基础,以便后续进行Netty的学习. 整 ...
- 用Netty开发中间件:网络编程基础
用Netty开发中间件:网络编程基础 <Netty权威指南>在网上的评价不是很高,尤其是第一版,第二版能稍好些?入手后快速翻看了大半本,不免还是想对<Netty权威指南(第二版)&g ...
- Linux 高性能服务器编程——Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字(so ...
- 【RL-TCPnet网络教程】第2章 嵌入式网络协议栈基础知识
第2章 嵌入式网络协议栈基础知识 本章教程为大家介绍嵌入式网络协议栈基础知识,本章先让大家有一个全面的认识,后面章节中会为大家逐一讲解用到的协议. 基础知识整理自百度百科,wiki百科等 ...
随机推荐
- SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - 自定义Servlet、Filter、Listener是如何注册到Tomcat容器中的?(SpringBoot实现SpringMvc的原理)
上一篇我们讲了SpringBoot中Tomcat的启动过程,本篇我们接着讲在SpringBoot中如何向Tomcat中添加Servlet.Filter.Listener 自定义Servlet.Filt ...
- python进程概要
进程 狭义:正在运行的程序实例. 广义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,他是操作系统动态执行的基本单元. python的进程都是并行的. 并行:两个进程同时执行一起走. ...
- 【Luogu P2146】软件包管理器
Luogu P2146 由于对于每一个软件包有且只有一个依赖的软件包,且依赖关系不存在环. 很显然这是一个树形的结构. 再看题目要求的操作,安装实际上对应的是覆盖根节点到当前节点的路径,卸载则是覆盖该 ...
- String类对象两种实例化方式比较
第一种:直接赋值 String str = "hello!" ; 在java中,有一个字符串常量池,对于这种直接赋值的,会直接写进常量池(常量池里面不存在其value,) 自JD ...
- 解决“无法完成域加入,原因是试图加入的域的SID与本计算机的SID相同
原文链接:http://www.cnblogs.com/xiaoyou2018/p/10677437.html Windows server 2012 R2 解决"无法完成域加入,原因是试图 ...
- react中简单倒计时跳转
其实在react中实现倒计时的跳转方法有很多中,其中我认为较为好用的就是通过定时器更改state中的时间值. 首先在constructor中设置10秒的时间值: constructor () { su ...
- 什么是WCF
WCF的全称是windows的通信基础 Windows Communication Foundation.本质上来讲,他是一套软件开发包. 服务终节点的三要素 用来发送接收消息的构造 创建一个WCF程 ...
- libnl的移植
libnl简介 libnl是为了方便应用程序使用netlink接口而开发的一个库.这个库为原始netlink消息传递以及不同的netlink,family专用接口提供了一个统一的接口.libnl2.0 ...
- C#语法--委托,架构的血液
委托的定义 什么是委托? 委托实际上是一种类型,是一种引用类型. 微软用delegate关键字来声明委托,delegate与int,string,double等关键字一样.都是声明用的. 下面先看下声 ...
- [UWP]使用CompositionGeometricClip裁剪复杂图形及进行动画
1. UWP中的其它裁剪方案 之前在 这篇文章 里,我介绍了如何使用UIElement.Clip裁剪UIElement的内容,使用代码如下: <Canvas> <Image Sour ...