Python网络编程(2)-粘包现象及socketserver模块实现TCP并发
1、 基于Tcp的远程调用命令实现
很多人应该都使用过Xshell工具,这是一个远程连接工具,通过上面的知识,就可以模拟出Xshell远程连接服务器并调用命令的功能。
Tcp服务端代码如下:
import socket,subprocess
ip_port = ("127.0.0.1",8000)
tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(5)
print("the server has started")
while True:
try:
conn,addr = tcp_server.accept()
cmd = conn.recv(1024)
if not cmd:break
res = subprocess.Popen(cmd.decode("utf-8"),shell=True,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE)
error = res.stderr.read()
if error:
cmd_res = error
else:
cmd_res = res.stdout.read()
if not cmd_res:
cmd_res = "the reply is".encode("gbk")
conn.send(cmd_res)
except Exception:
break
Tcp客户端代码如下:
import socket,subprocess
ip_port = ("127.0.0.1",8000)
tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
cmd = input(">>>>").strip()
if not cmd:continue
if cmd ==quit:break
tcp_client.send(cmd.encode("utf-8"))
cmd_res = tcp_client.recv(1024)
print("the reply is ",cmd_res.decode("gbk"))
tcp_client.close()
但在用上面两个代码进行模拟Xshell远程调用的过程中,可能会出现一个问题:粘包
2、 粘包
在数据信息传输过程中,发动数据的速度可能是3kb/s,但是接收数据的速度可能是10kb/s,甚至更快,应用程序看到的数据都是一个整体或可以说是一个流(stream),一条数据信息有多少字节,应用程序是不可见的。Tcp是面向连接,面向流的协议,这也就成为Tcp容易出现粘包现象的原因。基于Tcp的套接字客户端像服务端上传文件的时候,文件的内容是按照一个个小的字节段传输的,接收方根本不知道什么时候开始,什么时候结束。
而Udp将数据信息分成一个个小的数据段,在提取数据的时候,不能以字节为单位任意提取数据,只能以数据段为单位进行提取。所以只有Tcp才会出现粘包现象,而Udp就不会。
粘包问题主要造成原因就是接收方不知道数据消息之间的界限,(即开始点和终止点),不知道一次所需提取的数据是多少,所以造成的问题。
Tcp是基于数据流、面向连接的协议,因为收发的消息不能为空,在服务端和客户端都必须添加空消息的处理机制,防止程序运行过程中卡住。Udp是基于数据报、无连接的协议,即使发送的是空消息,但实质上它会将发送的空消息封装上消息头,不会收到影响。
在如下两种情况下很容易发生粘包现象:
(1) 发送数据时间的间隔太短,数据量很小,就会粘合在一种,产生粘包现象。
(2) 客户端发送数据后,服务端只接受一部分,再次发送其它数据的时候,服务端会先从缓冲区提取上一次的遗留数据,产生粘包。
解决粘包问题的根本就在于:要让接收方知道将要接收数据消息的长度。基于上面的Tcp远程调用命令的程序,该如何解决粘包问题?
服务端:
import socket,subprocess,struct
ip_port = ("127.0.0.1",8000)
tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(5)
print("the server has started")
while True:
while True:
conn,addr = tcp_server.accept()
try:
cmd = conn.recv(1024)
if not cmd:break
res = subprocess.Popen(cmd.decode("utf-8"),shell=True,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE)
error = res.stderr.read()
if error:
cmd_res = error
else:
cmd_res = res.stdout.read()
if not cmd_res:
cmd_res = "the reply is".encode("gbk")
length = len(cmd_res)
send_length = struct.pack("i",length)
conn.send(send_length,cmd_res)
except Exception:
break
客户端:
import socket,subprocess,struct
from functools import partial
ip_port = ("127.0.0.1",8000)
tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
cmd = input(">>>>").strip()
if not cmd:continue
if cmd ==quit:break
tcp_client.send(cmd.encode("utf-8")) recv_length = tcp_client.recv(4)
length = struct.unpack("i",recv_length)[0]
recv_msg = "".join(iter(partial(tcp_client.recv,1024),b""))
print("the reply is",recv_msg.decode("gbk"))
tcp_client.close()
3、 socketserver模块
在使用上面的程序进行通信时,是没有达到并发的。也就意味着,当第一个客户端占用服务端的资源的时候,第二个客户端再向服务端发起请求,是无法进行通信的。通过sockserver可以实现该功能。
sockserver是标准库中的一个高级模块,通过socketserver,将可以使用类来编写网络应用程序,以面向对象的方式的处理方式将更具有组织性和逻辑性。
socketserver包含了4个基本的类:基于TCP流式套接字的TCPServer;基于UDP数据报套接字的UDPServer,以及基于文件的基础同步UnixStreamServer和UnixDatagramServer。使用最多的TCPServer,后面三个很少用到。
在socketserver服务器框架中,基本所有的处理逻辑代码会放在一个请求处理程序中,(即一个类),服务端每当收到一个请求,就会实例化一个处理程序,并且调用相应的方法来响应客户端发来的请求,BaseRequestHandler类把所有的操作都放在handle方法中,这个方法会访问属性self.request中的客户端套接字。
服务端做如下改写:
import socketserver,struct
class Server2(socketserver.BaseRequestHandler):
def handle(self):
while True:
try:
data = self.request.recv(1024)
if not data:break
self.request.send(data.title())
except Exception:
break
if __name__ == "__main":
s = socketserver.ThreadingTCPServer(("127.0.0.1",8080),Server2)
s.serve_forever()
在这个程序中,self.request就等同于前面创建简单TCP服务端的conn,通过重写handle方法,该方法在默认情况下为空。当接收到一个客户端请求的时候,他就会调用handle()方法,然后通过socketserver.ThreadingTCPServer方法,传入给定的主机ip地址、端口号和所定义的类,最后使用serve_forever()方法来启动TCP服务器。无限循环的等待并服务于客户端请求。
Python网络编程(2)-粘包现象及socketserver模块实现TCP并发的更多相关文章
- python网络编程之粘包
一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个socket收发消息的原 ...
- Python网络编程,粘包、分包问题的解决
tcp编程中的粘包.分包问题的解决: 参考:https://blog.csdn.net/yannanxiu/article/details/52096465 服务端: #!/bin/env pytho ...
- python网络编程-socket“粘包”(小数据发送问题)
一:什么是粘包 “粘包”, 即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里,等缓冲区满了.或者数据等待超时了,数据才会 ...
- Python学习笔记【第十四篇】:Python网络编程二黏包问题、socketserver、验证合法性
TCP/IP网络通讯粘包问题 案例:模拟执行shell命令,服务器返回相应的类容.发送指令的客户端容错率暂无考虑,按照正确的指令发送即可. 服务端代码 # -*- coding: utf- -*- # ...
- Python之路 - 网络编程之粘包
Python之路 - 网络编程之粘包 粘包
- python/socket编程之粘包
python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...
- python socket网络编程之粘包问题详解
一,粘包问题详情 1,只有TCP有粘包现象,UDP永远不会粘包 你的程序实际上无权直接操作网卡的,你操作网卡都是通过操作系统给用户程序暴露出来的接口,那每次你的程序要给远程发数据时,其实是先把数据从用 ...
- Python之网路编程之粘包现象
一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个socket收发消息的原 ...
- UNIX网络编程——Socket粘包问题
一.两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收. 2.短连接 Client方与Server每进行一次报文收发交易 ...
随机推荐
- RocketMQ-顺序消费
看了https://www.jianshu.com/p/453c6e7ff81c这篇博客,得出顺序消费的结论."要实现严格的顺序消息,简单且可行的办法就是:保证生产者 - MQServer ...
- python3 第七章 - 循环语句
为了让计算机能计算成千上万次的重复运算,我们就需要循环语句. Python中的循环语句有 while for 循环语句的执行过程,如下图: while 循环 Python中while语句的一般形式: ...
- web项目各个clean
project clean:清楚tomcat下的已编译的java类.class文件,包括js但不包括jsp server clean:clean tomcat work dictionary:清除to ...
- 流API--原始类型流
到目前为止,我们已经将整型收集到了一个Stream<Integer>的流中,不过将每个整数包装成相应对象显然是一个低效的做法,对于其他的基本类型也是一样,我们前面说过jdk提供包装类已经自 ...
- svn: resource out of date; try updating的解决
问题: svn提交文件时提示错误:resource out of date; try updating.说明该资源版本有问题,尝试更新svn,发现该文件没有可更新的内容.于是查看资源历史,发现有人第一 ...
- 02_HTML5+CSS详解第一天
视频来源:麦子学院 讲师:朱朝兵 HTML5概念:HTML即超文本标记语言(HyperText Makeup Language),是一种语法简单,结构清晰的解释型文档,不同于其他编程语言. HTML5 ...
- 【转载】Linux时间相关结构与函数
1 时间的获取 在程序当中, 我们经常要输出系统当前的时间,比如日志文件中的每一个事件都要记录其产生时间.在 C 语言中获取当前时间的方法有以下几种,它们所获得的时间精度从秒级到纳秒,各有所不同. 表 ...
- Git远程管理[五]
标签(linux): git 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 相关命令 git clone https://github.com/guohongz ...
- windows程序设计获取文本框(窗口、对话框)文本
就是这样一个简单的界面,窗口上重绘的对话框(这种写法参考我之前博文): 需要做到的就是点击确定,获取文本框中内容. // 处理对话框消息 INT_PTR CALLBACK NewDlgProc(HWN ...
- 浅谈OSI七层模型及ICP/IP四层模型
1.OSI七层模型的概念 在网络历史的早期,国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)共同出版了开放系统互联的七层参考模型. 一台计算机操作系统中的网络过程包括从应用请求(在协议栈 ...