Python网络编程(2)-粘包现象及socketserver模块实现TCP并发
1、 基于Tcp的远程调用命令实现
很多人应该都使用过Xshell工具,这是一个远程连接工具,通过上面的知识,就可以模拟出Xshell远程连接服务器并调用命令的功能。
Tcp服务端代码如下:
1 import socket,subprocess 2 ip_port = ("127.0.0.1",8000) 3 tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 4 tcp_server.bind(ip_port) 5 tcp_server.listen(5) 6 print("the server has started") 7 while True: 8 try: 9 conn,addr = tcp_server.accept() 10 cmd = conn.recv(1024) 11 if not cmd:break 12 res = subprocess.Popen(cmd.decode("utf-8"),shell=True, 13 stdout=subprocess.PIPE, 14 stdin=subprocess.PIPE, 15 stderr=subprocess.PIPE) 16 error = res.stderr.read() 17 if error: 18 cmd_res = error 19 else: 20 cmd_res = res.stdout.read() 21 if not cmd_res: 22 cmd_res = "the reply is".encode("gbk") 23 conn.send(cmd_res) 24 except Exception: 25 break
Tcp客户端代码如下:
1 import socket,subprocess 2 ip_port = ("127.0.0.1",8000) 3 tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 4 tcp_client.connect(ip_port) 5 while True: 6 cmd = input(">>>>").strip() 7 if not cmd:continue 8 if cmd ==quit:break 9 tcp_client.send(cmd.encode("utf-8")) 10 cmd_res = tcp_client.recv(1024) 11 print("the reply is ",cmd_res.decode("gbk")) 12 tcp_client.close()
但在用上面两个代码进行模拟Xshell远程调用的过程中,可能会出现一个问题:粘包
2、 粘包
在数据信息传输过程中,发动数据的速度可能是3kb/s,但是接收数据的速度可能是10kb/s,甚至更快,应用程序看到的数据都是一个整体或可以说是一个流(stream),一条数据信息有多少字节,应用程序是不可见的。Tcp是面向连接,面向流的协议,这也就成为Tcp容易出现粘包现象的原因。基于Tcp的套接字客户端像服务端上传文件的时候,文件的内容是按照一个个小的字节段传输的,接收方根本不知道什么时候开始,什么时候结束。
而Udp将数据信息分成一个个小的数据段,在提取数据的时候,不能以字节为单位任意提取数据,只能以数据段为单位进行提取。所以只有Tcp才会出现粘包现象,而Udp就不会。
粘包问题主要造成原因就是接收方不知道数据消息之间的界限,(即开始点和终止点),不知道一次所需提取的数据是多少,所以造成的问题。
Tcp是基于数据流、面向连接的协议,因为收发的消息不能为空,在服务端和客户端都必须添加空消息的处理机制,防止程序运行过程中卡住。Udp是基于数据报、无连接的协议,即使发送的是空消息,但实质上它会将发送的空消息封装上消息头,不会收到影响。
在如下两种情况下很容易发生粘包现象:
(1) 发送数据时间的间隔太短,数据量很小,就会粘合在一种,产生粘包现象。
(2) 客户端发送数据后,服务端只接受一部分,再次发送其它数据的时候,服务端会先从缓冲区提取上一次的遗留数据,产生粘包。
解决粘包问题的根本就在于:要让接收方知道将要接收数据消息的长度。基于上面的Tcp远程调用命令的程序,该如何解决粘包问题?
服务端:
1 import socket,subprocess,struct 2 ip_port = ("127.0.0.1",8000) 3 tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 4 tcp_server.bind(ip_port) 5 tcp_server.listen(5) 6 print("the server has started") 7 while True: 8 while True: 9 conn,addr = tcp_server.accept() 10 try: 11 cmd = conn.recv(1024) 12 if not cmd:break 13 res = subprocess.Popen(cmd.decode("utf-8"),shell=True, 14 stdout=subprocess.PIPE, 15 stdin=subprocess.PIPE, 16 stderr=subprocess.PIPE) 17 error = res.stderr.read() 18 if error: 19 cmd_res = error 20 else: 21 cmd_res = res.stdout.read() 22 if not cmd_res: 23 cmd_res = "the reply is".encode("gbk") 24 length = len(cmd_res) 25 send_length = struct.pack("i",length) 26 conn.send(send_length,cmd_res) 27 except Exception: 28 break
客户端:
1 import socket,subprocess,struct 2 from functools import partial 3 ip_port = ("127.0.0.1",8000) 4 tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 5 tcp_client.connect(ip_port) 6 while True: 7 cmd = input(">>>>").strip() 8 if not cmd:continue 9 if cmd ==quit:break 10 tcp_client.send(cmd.encode("utf-8")) 11 12 13 recv_length = tcp_client.recv(4) 14 length = struct.unpack("i",recv_length)[0] 15 recv_msg = "".join(iter(partial(tcp_client.recv,1024),b"")) 16 print("the reply is",recv_msg.decode("gbk")) 17 tcp_client.close()
3、 socketserver模块
在使用上面的程序进行通信时,是没有达到并发的。也就意味着,当第一个客户端占用服务端的资源的时候,第二个客户端再向服务端发起请求,是无法进行通信的。通过sockserver可以实现该功能。
sockserver是标准库中的一个高级模块,通过socketserver,将可以使用类来编写网络应用程序,以面向对象的方式的处理方式将更具有组织性和逻辑性。
socketserver包含了4个基本的类:基于TCP流式套接字的TCPServer;基于UDP数据报套接字的UDPServer,以及基于文件的基础同步UnixStreamServer和UnixDatagramServer。使用最多的TCPServer,后面三个很少用到。
在socketserver服务器框架中,基本所有的处理逻辑代码会放在一个请求处理程序中,(即一个类),服务端每当收到一个请求,就会实例化一个处理程序,并且调用相应的方法来响应客户端发来的请求,BaseRequestHandler类把所有的操作都放在handle方法中,这个方法会访问属性self.request中的客户端套接字。
服务端做如下改写:
1 import socketserver,struct 2 class Server2(socketserver.BaseRequestHandler): 3 def handle(self): 4 while True: 5 try: 6 data = self.request.recv(1024) 7 if not data:break 8 self.request.send(data.title()) 9 except Exception: 10 break 11 if __name__ == "__main": 12 s = socketserver.ThreadingTCPServer(("127.0.0.1",8080),Server2) 13 s.serve_forever()
在这个程序中,self.request就等同于前面创建简单TCP服务端的conn,通过重写handle方法,该方法在默认情况下为空。当接收到一个客户端请求的时候,他就会调用handle()方法,然后通过socketserver.ThreadingTCPServer方法,传入给定的主机ip地址、端口号和所定义的类,最后使用serve_forever()方法来启动TCP服务器。无限循环的等待并服务于客户端请求。
转载于:https://www.cnblogs.com/Chen-Zhipeng/p/8488901.html
Python网络编程(2)-粘包现象及socketserver模块实现TCP并发相关推荐
- 网络编程-之粘包现象
网络编程-之粘包现象 一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个s ...
- 【Python】网络编程--解决粘包问题--简单版:
网络编程–解决粘包问题–简单版: 客户端: import struct import socketphone=socket.socket(socket.AF_INET,socket.SOCK_STRE ...
- python/socket编程之粘包
python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 发 ...
- Python之网络编程(粘包、粘包解决方案)
文章目录 tcp粘包 第一种粘包 第二种粘包 udp粘包 解决粘包现象 粘包现象是指发送方发送的若干数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.粘包现象只会在tcp ...
- python网络编程之黏包问题
一 : 概念 发送端发送数据,接收端不知道应该如何去接收,造成的一种数据混乱的现象. 二 : 起因 在TCP协议中,存在两个机制: 合包机制 : 通过nagle算法,将多次连续发送且间隔较小的数据,打 ...
- 网络编程中客户端链接的合法性,socketserver模块
客户端链接的合法性 验证合法性: 首先,我们来探讨一下,什么叫验证合法性, 举个例子:有一天,我开了一个socket服务端,只想让咱们这个班的同学使用,但是有一天,隔壁班的同学过来问了一下我开的这个服 ...
- 网络编程- 解决黏包现象方案一(六)
队列 利用队列的思路来解决黏包问题 总结 转载于:https://www.cnblogs.com/mys6/p/10797907.html
- python 网络编程 struct解包时报错 struct.error: unpack requires a buffer of 4 bytes
报错信息 D:\Donta_tensorflow-yolov3\python\python.exe D:/10_gitee/network_programming/避障程序信号及图像接收端/20100 ...
- 10.python网络编程(解决粘包问题 part 2)
一.什么时候会产生粘包现象. 只有在使用tcp协议的情况下才会产生粘包现象!udp协议永远不会! 发送端可以1k1k的把数据发送出去,接收端,可以2k2k的的去接收数据,一次可能会接收3k,也有可能1 ...
- 学习笔记(10):Python网络编程并发编程-粘包现象
立即学习:https://edu.csdn.net/course/play/24458/296240?utm_source=blogtoedu 粘包现象:服务器接收到客户端的命令后,进行执行得到结果后 ...
最新文章
- One order popup window 显示逻辑
- 电脑运行adb闪退_adb+python进阶使用
- 以容器为代表的云原生技术,正成为释放云价值最短路径
- php oci8 11,linux下为php开启oci8扩展(ubuntu14亲测可用)
- python实现端口转发_Python TCP/IP协议下实现端口转发及重定向菜鸟教程
- mac下配置进行c和matlab混编
- 精度P,召回率R和F值
- linux密码加密方式 2y,手动生成Linux密码(/etc/shadow)
- 详解GaussDB(for MySQL)服务:复制策略与可用性分析
- centos7安装java6_CentOS7.6安装openjdk
- 微软发布 VS Code Jupyter 插件!不止 Python,多语言的 Jupyter Notebook支持来了!
- ARM架构与系列简介
- 华为p30pro鸿蒙悟空,华为新广告《悟空》火了,竟是华为P30Pro拍的?
- 100base - CX/FX/LX/SX/ZX
- Java URI 和 android Uri 中的 getSchemeSpecificPart() 方法
- sass、scss、和css的关系
- MySQL入门:数据库是什么 | SQL是什么 | MySQL是什么
- 车牌生成代码车牌后5位生成代码
- 从C程序到bin文件
- InfoPath 系列:表单的发布与共享
热门文章
- 【渝粤教育】国家开放大学2018年春季 7392-21DMatlab语言及其应用 参考试题
- 【渝粤教育】国家开放大学2018年春季 7067-22T康复护理学 参考试题
- 【渝粤教育】国家开放大学2019年春季 45烹饪原料学(1) 参考试题
- 【渝粤教育】国家开放大学2018年春季 0266-22T设计构成 参考试题
- 【渝粤教育】电大中专新媒体营销实务 (14)作业 题库
- BZOJ3527 推出卷积公式FFT求值
- subprocess模块(了解)
- DAY37-Python入门学习-进程池与线程池、协程、gevent模块
- 多线程编程核心技术日记
- Ubunt 服务教程集锦