码迷,mamicode.com
首页 > 编程语言 > 详细

Python-IO多路复用

时间:2018-02-22 23:53:44      阅读:407      评论:0      收藏:0      [点我收藏+]

标签:als   通过   表示   blocking   lis   一个   key   平台   .com   

select实现socket server多并发服务器端

# -*- coding:utf-8 -*-
__author__ = "MuT6 Sch01aR"

import socket
import select
import queue

server = socket.socket()
server.bind((‘127.0.0.1‘, 9999))
server.listen()

server.setblocking(False)  # 要设置为非阻塞

input_list = [server, ]  # 本身也要检测
output_list = []
msg_dic = {}

while True:
    stdinput, stdoutput, stderr = select.select(input_list, output_list, input_list)
    # 第一个input_list参数为要用的连接,ouput_list为可能返回的连接,第二个input_list为可能报错的连接
    # stdinput为连接的地址, stdoutput为返回的连接, stderr为错误的连接
    print(stdinput, stdoutput, stderr)
    try:
        for r in stdinput:
            if r is server:  # 来了个新连接
                conn, addr = server.accept()
                print(‘当前连接客户端:‘, addr)
                input_list.append(conn)
                msg_dic[conn] = queue.Queue()  # 初始化一个队列,用来储存要返回给客户端的数据
            else:
                    data = r.recv(1024)
                    print(‘收到数据‘, data)
                    msg_dic[r].put(data)
                    output_list.append(r)  # 放入返回的连接队列里
    except socket.error:
        print(‘客户端断开连接‘)
        break

    for w in stdoutput:  # 要返回给客户端的连接列表
        data_to_client = msg_dic[w].get()
        w.send(data_to_client)  # 把数据发送给客户端
        output_list.remove(w)  # 确保下次循环的时候stdoutput不返回已经处理完的连接

    for e in stderr:
        if e in output_list:
            output_list.remove(e)
        input_list.remove(e)
        server.close()
        del msg_dic[e]

客户端

# -*- coding:utf-8 -*-
__author__ = "MuT6 Sch01aR"

import socket

client = socket.socket()
client.connect((‘127.0.0.1‘, 9999))

while True:
    msg = input(‘>>>:‘).strip()
    if len(msg) ==0:continue
    client.send(msg.encode(‘utf-8‘))
    data = client.recv(1024)
    print(data)

selector模块

selector模块可以使用select和epoll,它会根据所处的平台来选出最适合的I/O多路复用机制,在windows下为select,在linux下为epoll

通过selector模块实现单线程上万并发的socket server

服务器端

# -*- coding:utf-8 -*-
__author__ = "MuT6 Sch01aR"

import selectors
import socket

sel = selectors.DefaultSelector()

def accept(sock, mask):
    conn, addr = sock.accept()
    print(‘当前连接客户端‘, addr)
    conn.setblocking(False)  # 把连接设置为非阻塞
    sel.register(conn, selectors.EVENT_READ, read)  # 新连接注册read回调函数,如果新的连接发送数据就执行read函数

def read(conn, mask):
    data = conn.recv(1024)
    if data:
        print(‘收到数据:‘,data)
        conn.send(data)
    else:
        print(‘客户端关闭‘, conn)
        sel.unregister(conn)  # 注销注册的事件
        conn.close()

server = socket.socket()
server.bind((‘localhost‘, 9999))
server.listen()
server.setblocking(False)
sel.register(server, selectors.EVENT_READ, accept)  # 注册一个事件,如果来了连接,就调用accept函数
# EVENT_READ,表示可读,值mask为1,EVENT_WRITE表示可写,值mask为2

while True:
    events = sel.select()  # 调用epoll或select,默认阻塞,有活动的连接就返回活动的连接列表
    for key, mask in events:
        callback = key.data  # 回调函数,即accept函数
        callback(key.fileobj, mask)  # key.fileobj为文件句柄,即还没建立连接的socket实例

sel.close() # 最后要关闭,确保所有的资源被释放

客户端

# -*- coding:utf-8 -*-
__author__ = "MuT6 Sch01aR"

import socket
import sys

msg = [
        b‘python‘,
        b‘php‘,
        b‘java‘,
      ]

server_address = (‘127.0.0.1‘, 9999)

socks = [socket.socket(socket.AF_INET, socket.SOCK_STREAM) for i in range(300)]

print(‘connecting to %s port %s‘ % server_address)
for s in socks:
    s.connect(server_address)

for m in msg:
    for s in socks:
        print(‘%s: sending "%s"‘ % (s.getsockname(), m))
        s.send(m)

    for s in socks:
        data = s.recv(1024)
        print(‘%s: received "%s"‘ % (s.getsockname(), data))
        if not data:
            print(sys.stderr, ‘closing socket‘, s.getsockname())

服务器端运行结果

技术分享图片

客户端运行结果

技术分享图片

300个socket连接1秒左右就全结束了

Python-IO多路复用

标签:als   通过   表示   blocking   lis   一个   key   平台   .com   

原文地址:https://www.cnblogs.com/sch01ar/p/8460488.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!