非阻塞套接字实现并发

上篇博客介绍的套接字因为其阻塞性导致线程可能会被一直占用,从而造成一个服务端只能连接一个客户端的现象。在python中,可以将套接字设置为非阻塞型,即在套接字实例化后将setblocking方法的参数改为False。下面看一下非阻塞套接字和阻塞套接字的区别。

  • accept会从原先的阻塞变成疏通,但如果没有连接过来它会报BlockingIOError异常。

  • recv会从原先的阻塞变成疏通,但如果没有数据过来它也会报BlockingIOError异常。

  • 没有连接的情况下,send会报OSError异常。

  • 在客户端,connect连接一定会报BlockingIOError异常。

对于上述的异常处理,我们统一用try...except。

运用非堵塞套接字实现堵塞套接字

用非堵塞的accept实现堵塞的accept机制

while True:
    try:
        a,b = server.accept()
    except BlockingIOError as error:
        pass

用非堵塞的recv实现堵塞的recvt机制

 while True:
        try:
            date = i.recv(1024)
            if date:
                print("已收到信息-->{}".format(date.decode()))
                i.send(date)
            else:
                i.close()
        except BlockingIOError as error:
            pass

实现并发

非堵塞的套接字可以吃满CPU,不会堵塞发呆。因为其非堵塞,故可以实现并发,让服务端可以同时连接多个客户端。下面是服务端的代码。

import socket

server = socket.socket()
server.setblocking(False)
server.bind(('127.0.0.5',8520))
server.listen(50)
conn_list = []
while True:
    try:
        a,b = server.accept()
        conn_list.append(a)
    except BlockingIOError as error:
        pass
    for i in conn_list:
        try:
            date = i.recv(1024)
            if date:
                print("已收到信息-->{}".format(date.decode()))
                i.send(date)
            else:
                i.close()
                conn_list.remove(i)
        except BlockingIOError as error:
            pass

客户端的套接字还是保持堵塞,如下:

import socket

client = socket.socket()
client.connect(('127.0.0.5',8520))
mess = input('--->').encode()
client.send(mess)
print("已收到回应-->{}".format(client.recv(1024)))
client.close()

这时可以对此运行客户端的代码,让服务端同时连接上多个客户端,然后对客户端任意次序地对服务端发送信息,结果能达到并发的效果。

缺点:运用非阻塞套接字实现的并发虽然可以解决一次与多个客户端连接,但如果没有连接过来,那么accept和recv即send都是无效的,这大大浪费了CPU的利用率,其中的报错也是无效的CPU花费。

下篇博客将会讲下如何提高CPU的利用率。

posted @ 2018-10-18 22:30  龙~白  阅读(510)  评论(0编辑  收藏  举报