socket使用epoll的一个问题

发布于 2022-09-02 12:18:00 字数 5849 浏览 13 评论 0

代码如下,使用epoll创建的一个异步socket的服务器(代码基本为http://scotdoyle.com/python-epoll-howto....中的Example 3,只不过加了一些日志打印)

import os
import select
import socket
import logging
import time

eventmasks = {
    "EPOLLERR": 8,
    "EPOLLET": 2147483648,
    "EPOLLHUP": 16,
    "EPOLLIN": 1,
    "EPOLLMSG": 1024,
    "EPOLLONESHOT": 1073741824,
    "EPOLLOUT": 4,
    "EPOLLPRI": 2,
    "EPOLLRDBAND": 128,
    "EPOLLRDNORM": 64,
    "EPOLLWRBAND": 512,
    "EPOLLWRNORM": 256,
}

eventmask_ids = {
    1: "EPOLLIN",
    2: "EPOLLPRI",
    4: "EPOLLOUT",
    8: "EPOLLERR",
    16: "EPOLLHUP",
    64: "EPOLLRDNORM",
    128: "EPOLLRDBAND",
    256: "EPOLLWRNORM",
    512: "EPOLLWRBAND",
    1024: "EPOLLMSG",
    1073741824: "EPOLLONESHOT",
    2147483648: "EPOLLET"
}

formatter = "[%(asctime)-15s] [%(levelname)s] %(message)s"
logging.basicConfig(level=logging.DEBUG, format=formatter)

EOL1 = b'\n\n'
EOL2 = b'\n\r\n'

response  = b'HTTP/1.0 200 OK\r\nDate: %s\r\n'
response += b'Content-Type: text/plain\r\nContent-Length: %s\r\n\r\n%s'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("0.0.0.0", 9999))
s.listen(1024)
s.setblocking(0)

epoll = select.epoll()
s_fileno = s.fileno()
epoll.register(s, select.EPOLLIN)

try:
    connections = {}
    request_data = {}
    response_data = {}
    actions = {}
    while True:
        events = epoll.poll(24)
        for fileno, event in events:
            logging.debug(">>>>>" * 12)
            logging.debug("Event file number is %s and event mask is %s(%s)", fileno, bin(event), eventmask_ids.get(event, 0))
            if fileno == s_fileno:
                # create new socket connection from client
                conn, address = s.accept()
                conn.setblocking(0)
                c_fileno = conn.fileno()
                logging.debug("Connection from client%s file number is %s", address, c_fileno)
                epoll.register(c_fileno, select.EPOLLIN)
                connections[c_fileno] = conn
                request_data[c_fileno] = b""
                response_data[c_fileno] = b""
                actions[c_fileno] = []
            elif event & select.EPOLLIN:
                logging.info("Recive data epoll socket file number is %s, actions are: %s", fileno, actions[fileno])
                actions[fileno].append("recv")
                # data come in
                data_piece = connections[fileno].recv(1024)
                # logging.debug("Recive client data piece is:\n%s", data_piece)
                request_data[fileno] += data_piece
                if EOL1 in request_data[fileno] or EOL2 in request_data[fileno]:
                    resp = str(os.environ)
                    response_data[fileno] = response % (time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()), len(resp), resp)
                    epoll.modify(fileno, select.EPOLLOUT)
                    # logging.debug("Data from client is: \n%s", request_data[fileno])
                if request_data[fileno] == b"":
                    logging.error("Recive empty data")
                    epoll.unregister(fileno)
                    connections[fileno].close()
            elif event & select.EPOLLOUT:
                actions[fileno].append("send")
                # send data to client
                # logging.warn("Full connections are %s", connections)
                logging.info("Send data epoll socket file number is %s", fileno)
                send_bytes = connections[fileno].send(response_data[fileno])
                response_data[fileno] = response_data[fileno][send_bytes:]
                if len(response_data[fileno]) == 0:
                    actions[fileno].append("shutdown")
                    epoll.modify(fileno, 0)
                    logging.info("I will shutdown socket(%s), actions are: %s", connections[fileno], actions[fileno])
                    connections[fileno].shutdown(socket.SHUT_RDWR)
                    del response_data[fileno]
            elif event & select.EPOLLHUP:
                actions[fileno].append("close")
                logging.info("Close data epoll scoket file number is %s, actions are: %s", fileno, actions[fileno])
                # connection close by client
                epoll.unregister(fileno)
                connections[fileno].close()
                del connections[fileno]
                del actions[fileno]
            logging.debug("<<<<<" * 12)
finally:
    logging.error("Exception happend, closing server...")
    epoll.unregister(s_fileno)
    epoll.close()
    s.close()

运行以后可以访问,但使用压测软件测试会抛出[Errno 107] Transport endpoint is not connected这样的异常

图片描述

压测命令为siege -c 100 -i -b --delay=0 --time=1s http://172.17.0.1:9999,而压测结果显示可用100%

** SIEGE 3.0.5
** Preparing 100 concurrent users for battle.
The server is now under siege...
Lifting the server siege... done.

Transactions: 868 hits
Availability: 100.00 %
Elapsed time: 0.93 secs
Data transferred: 1.49 MB
Response time: 0.09 secs
Transaction rate: 933.33 trans/sec
Throughput: 1.60 MB/sec
Concurrency: 87.33
Successful transactions: 868
Failed transactions: 0
Longest transaction: 0.12
Shortest transaction: 0.01

关于[Errno 107] Transport endpoint is not connected这个错误,应该是tcp连接并没有建立,但是,我上面的代码和日志显示连接已经建立,为什么还会抛出这个异常

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文