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平台无法使用ForkingUDPServerForkingTCPServer的原因

首先知道,Python在Linux平台创建进程,其实是使用fork来做的系统调用,而在Windows平台,则是使用createprocess做的系统调用。
然后,在socketserver中使用多进程实现socket并发,使用的是ForkingUDPServerForkingTCPServer这两个类,来看调用关系:

# 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判断不会执行,那么ForkingUDPServerForkingTCPServer类也不会创建,所以也就无法使用,下面示例确认了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:

python基础之socket编程 | IO模型

posted @ 2020-10-13 10:59  听雨危楼  阅读(216)  评论(0编辑  收藏  举报