Python 网络编程
上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端、服务器程序,本篇博客主要对socket编程进行更深入的讲解
一、简化版ssh实现
这是一个极其简单的仿ssh的socket程序,实现的功能为客户端发送命令,服务端接收到客户端的命令,然后在服务器上通过subrocess模块执行命令,如果命令执行有误,输出内容为空,则返回"command error"的语句给客户端,否则将命令执行的结果返回给客户端
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
上面的程序有个问题,如果命令执行的结果比较长,那么客户端发送下一个命令过去之后仍然返回上一个命令没接收完的结果,这样的现象我们称作粘包的现象。我们知道TCP传输的是数据流,发送数据时会等缓冲区满了然后再发送,或者等待要发送的时间超时了再发送,几个包组合在一起发送可以提高发送效率,此时也造成了粘包现象的产生,目标机器一次性接收几个包的数据,可能导致本次请求接收多余的数据。粘包还有一种情况,就是本次程序里面出现的情况,因为服务端要发送的数据大于1024,导致客户端无法一次性接收完数据,虽然我们可以修改接收的大小,但是治标不治本。解决方法有我们在发送具体数据前,先将数据的大小发送给客户端,客户端做好接收准备并告诉给服务端,服务端一次性发送数据之后,客户端根据服务器端发送数据的大小进行循环接收,直到数据接收完毕。
改进版
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
二、IO多路复用
IO多路复用指通过一种机制,可以监视多个描述符,一旦某个描述符就绪,就能够通过程序进行相应的读写操作
Python中有一个select模块,其中提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用
对于select:
1 2 3 4 5 6 7 8 9 10 11 |
|
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
三、SocketServer
SocketServer内部使用 IO多路复用 以及多线程和多进程,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求
SocketServer有以下几种类型:
- socketserver.TCPServer
- socketserver.UDPServer
- socketserver.UnixStreamServer
- socketserver.UnixDatagramServer
?每种类型都可以通过多线程或者多进程的方式处理多个客户的请求,这里介绍ThreadingTCPServer的使用方式:
- 创建一个继承自 SocketServer.BaseRequestHandler 的类
- 类中必须定义一个名称为 handle 的方法
- 启动ThreadingTCPServer
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|