1-Python - IO模型
before
win10 + python3.6
socketserver封装了socket的复杂性,提供简单的接口就可以进行socket通信,并且支持并发,是一个非常友好且简单的模块。
想要进一步了解socketserver源码实现,你需要掌握socket、I/O多路复用、并发等知识;除此之外,你还要知道我们自己如何一步步的实现socket并发通信,然后才能畅读socketserver源码。
本篇我们主要通过自己一步一步实现并发通信,然后再通过示例来研究socketserver的源码。
自己实现并发
先来个
socket简单通信:server端
import socket
sock = socket.socket()
address = '127.0.0.1', 8888
sock.bind(address)
sock.listen(5)
conn, addr = sock.accept()
print(conn, addr) # <socket.socket fd=344, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8888), raddr=('127.0.0.1', 63579)> ('127.0.0.1', 63579)
msg = conn.recv(1024)
conn.send(msg)
conn.close()
sock.close()
socket简单通信:client端
import socket
sock = socket.socket()
address = '127.0.0.1', 8888
sock.connect(address)
sock.send('hello'.encode())
msg = sock.recv(1024)
print(msg.decode())
sock.close()
进阶版的
socket实现与单个客户端循环通信:server端
import socket
sock = socket.socket()
address = '127.0.0.1', 8888
sock.bind(address)
sock.listen(5)
conn, addr = sock.accept()
while True: # 通信循环,通过该循环,可以实现和单个客户端进行反复收发消息
msg = conn.recv(1024)
if not msg: break
if msg.decode().lower() == 'close': break
conn.send(msg)
conn.close()
sock.close()
socket实现与单个客户端循环通信:client端
import socket
sock = socket.socket()
address = '127.0.0.1', 8888
sock.connect(address)
while True:
data = input('>>: ').strip()
if not data: continue
if data.lower() == 'close': break
sock.send(data.encode())
msg = sock.recv(1024)
print(msg.decode())
sock.close()
再进阶版
socket实现server端与多个client端通信:sever端
import socket
sock = socket.socket()
address = '127.0.0.1', 8888
sock.bind(address)
sock.listen(5)
while True: # 连接循环,通过该循环,可以实现和多个客户端进行连接
conn, addr = sock.accept()
while True: # 通信循环,通过该循环,可以实现和单个客户端进行反复收发消息
msg = conn.recv(1024)
if not msg: break
if msg.decode().lower() == 'close': break
conn.send(msg)
conn.close()
sock.close()
socket实现server端与多个client端通信:client端
import socket
sock = socket.socket()
address = '127.0.0.1', 8888
sock.connect(address)
while True:
data = input('>>: ').strip()
if not data: continue
if data.lower() == 'close': break
sock.send(data.encode())
msg = sock.recv(1024)
print(msg.decode())
sock.close()
关于在Windows平台无法使用ForkingUDPServer
和ForkingTCPServer
的原因
首先知道,Python在Linux平台创建进程,其实是使用fork来做的系统调用,而在Windows平台,则是使用createprocess做的系统调用。
然后,在socketserver中使用多进程实现socket并发,使用的是ForkingUDPServer
和ForkingTCPServer
这两个类,来看调用关系:
# test.py
import socketserver
socketserver.ForkingTCPServer
socketserver.ForkingUDPServer
上例是我们在脚本中如何实现多进程并发,那么来看上述两个类在socketserver.py
中的的源码:
if hasattr(os, "fork"): # 首先根据 os 的 fork 属性判断是否创建 下面的两个类
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
之前说了,在Windows平台中使用的是createprocess发起的创建进程的系统调用,所以,Windows平台中的os模块没有fork属性,导致上述源码的if判断不会执行,那么ForkingUDPServer
和ForkingTCPServer
类也不会创建,所以也就无法使用,下面示例确认了Windows平台的os没有fork属性:
[root@cs ~]# python3
Python 3.6.8 (default, Aug 20 2020, 19:34:21)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> 'fork' in dir(os)
True
>>> os.fork
<built-in function fork>
C:\Users\Anthony>python36
Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> 'fork' in dir(os)
False
>>> os.fork
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'os' has no attribute 'fork'
that's all,see also: