Python epoll 服务端编程

版权声明:本文为博主原创文章,转载请注明原文出处。 https://blog.csdn.net/woay2008/article/details/84490842

在《UNIX网络编程 卷1》这一节 中,我们曾用C语言实现了一个使用epoll的TCP回显服务器程序。现在我们用 Python 来实现同样的功能,代码如下:

# -*- coding: utf-8 -*-
import os
import socket
import select

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setblocking(False)
s.bind(('127.0.0.1', 22222))
s.listen(5)

sockets = {}
epoll = select.epoll()
epoll.register(s.fileno(), select.EPOLLIN)

while True:
    events = epoll.poll()

    for fd, event in events:

        if fd == s.fileno():  # 新的连接请求
            c, addr = s.accept()
            c.setblocking(False) # 非阻塞
            sockets[c.fileno()] = c
            epoll.register(c.fileno(), select.EPOLLIN) # 水平触发的方式

        else:  # 新的数据
            c = sockets[fd]
            close = False

            try:
                data = c.recv(1024)
            except socket.error:
                close = True

            if data:
                try:
                    c.send(data)
                except socket.error:
                    close = True
            else:
                close = True

            if close: # socket上出现错误或对端正常关闭连接时,关闭socket
                epoll.unregister(fd)
                del sockets[fd]
                c.close()

注意,上述实现使用的是epoll的水平触发方式,如果要使用epoll的边沿触发方式,则代码如下:

# -*- coding: utf-8 -*-
import os
import errno
import socket
import select

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setblocking(False)
s.bind(('127.0.0.1', 22222))
s.listen(5)

sockets = {}
epoll = select.epoll()
epoll.register(s.fileno(), select.EPOLLIN)

while True:
    events = epoll.poll()

    for fd, event in events:

        if fd == s.fileno():  # 新的连接请求
            c, addr = s.accept()
            c.setblocking(False) # 非阻塞
            sockets[c.fileno()] = c
            epoll.register(c.fileno(), select.EPOLLIN | select.EPOLLET) # 边沿触发的方式

        else:  # 新的数据
            c = sockets[fd]
            close = False

            while True:
                try:
                    data = c.recv(1024)
                except socket.error, err:
                    if err[0] != errno.EAGAIN:
                        close = True
                    break

                if data:
                    try:
                        c.send(data)
                    except socket.error, err:
                        if err[0] != errno.EAGAIN:
                            close = True
                        break
                else:
                    close = True
                    break

            if close: # socket上出现错误或对端正常关闭连接时,关闭socket
                epoll.unregister(fd)
                del sockets[fd]
                c.close()

上述的代码只是个参考,还有一些细节问题没有考虑。比如,send发送数据时,如果返回EAGAIN,正确的情形下该如何处理?

猜你喜欢

转载自blog.csdn.net/woay2008/article/details/84490842
今日推荐