用select (多路复用)模拟一个 socket server

需求:用select (多路复用)模拟一个 socket server。可以接收多并发。

1. 一开始是检测自己,如果我有活动了,就说明有客户端要连我了。

#用select去模拟socket,实现单线程下的多路复用

import select
import socket
import queue 

server=socket.socket()
server.bind(('localhost',9000))
server.listen(1024)

 

server.setblocking(False) #设置为不阻塞,accept/recv没有数据都不阻塞,只会报错。

 

inputs=[server,] #先检测自己,如果我有活动了,说明有客户端要连我了。

outputs=[]

 

select.select(inputs,outputs,inputs)

#第一个参数:操作系统发现100个里面有1个在活动,就会返回这100个。需要检测哪些链接就放进来。

#第二个参数:

#第三个参数:让操作系统检测100个的哪个有问题,就把有问题的返回。

server.accept()

 运行结果:卡住了,有客户端进来时才会不卡。

C:\abccdxddd\Oldboy\python-3.5.2-embed-amd64\python.exe C:/abccdxddd/Oldboy/Py_Exercise/Day10/select_socket_server.py

 2.服务器端

#用select去模拟socket,实现单线程下的多路复用

 

import select

import socket

import queue

 

server=socket.socket()

server.bind(('localhost',9000))

server.listen(1024)

 

server.setblocking(False) #设置为不阻塞,accept/recv没有数据都不阻塞,只会报错。

 

inputs=[server,] #先检测自己,如果我有活动了,说明有客户端要连我了。

#inputs=[server,conn]

outputs=[]

while True:

    readable,writeable,exceptional=select.select(inputs,outputs,inputs)

    #第一个参数:操作系统发现100个里面有1个在活动,就会返回这100个。需要检测哪些链接就放进来。

    #第二个参数:

    #第三个参数:让操作系统检测100个的哪个有问题,就把有问题的返回。

    print(readable,writeable,exceptional)

    for r in readable:

        if r is server: #代表来了一个新链接

            conn,addr=server.accept()

            print('来了个新链接',addr)

            inputs.append(conn) #是因为这个新建立的连接还没有发数据过来,现在就接收的话,程序会报错。

            #所以要想实现这个客户端发数据来时server端能知道,就需要让select再监测这个Conn。

        else:

            data=conn.recv(1024)

            print('收到数据',data)

            conn.send(data)

 客户端:

import socket

HOST = 'localhost'  # The remote host

PORT = 9000  # The same port as used by the server

 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((HOST, PORT))

 

while True:

    msg = bytes(input(">>:"), encoding="utf8")

    s.sendall(msg)

    data = s.recv(1024)

    # print(data)

    print('Received', repr(data))  #repr:格式化输出

 

s.close()

 

 运行结果: 有2个链接的情况下,无法多次接收数据

 

C:\abccdxddd\Oldboy\python-3.5.2-embed-amd64\python.exe C:/abccdxddd/Oldboy/Py_Exercise/Day10/select_socket_server.py

[<socket.socket fd=240, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000)>] [] []

来了个新链接 ('127.0.0.1', 53605)

[<socket.socket fd=336, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 53605)>] [] []

收到数据 b'1'

[<socket.socket fd=240, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000)>] [] []

来了个新链接 ('127.0.0.1', 60337)

[<socket.socket fd=348, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 60337)>] [] []

收到数据 b'123'

 

 3. server端进行修改:

 

#用select去模拟socket,实现单线程下的多路复用

 

import select

import socket

import queue

 

server=socket.socket()

server.bind(('localhost',9000))

server.listen(1024)

 

server.setblocking(False) #设置为不阻塞,accept/recv没有数据都不阻塞,只会报错。

 

inputs=[server,] #先检测自己,如果我有活动了,说明有客户端要连我了。

#inputs=[server,conn]

outputs=[]

while True:

    readable,writeable,exceptional=select.select(inputs,outputs,inputs)

    #第一个参数:操作系统发现100个里面有1个在活动,就会返回这100个。需要检测哪些链接就放进来。

    #第二个参数:

    #第三个参数:让操作系统检测100个的哪个有问题,就把有问题的返回。

    print(readable,writeable,exceptional)

    for r in readable:

        if r is server: #代表来了一个新链接

            conn,addr=server.accept()

            print('来了个新链接',addr)

            inputs.append(conn) #是因为这个新建立的连接还没有发数据过来,现在就接收的话,程序会报错。

            #所以要想实现这个客户端发数据来时server端能知道,就需要让select再监测这个Conn。

        else:

            data=r.recv(1024)

            print('收到数据',data)

            r.send(data) 


 至此运行正常

 

 

posted on 2017-08-17 20:45  momo8238  阅读(330)  评论(0编辑  收藏  举报