search

Home  >  Q&A  >  body text

python - socket使用epoll的一个问题

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

<code class="python">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()</code>

运行以后可以访问,但使用压测软件测试会抛出[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连接并没有建立,但是,我上面的代码和日志显示连接已经建立,为什么还会抛出这个异常

PHP中文网PHP中文网2887 days ago421

reply all(0)I'll reply

No reply
  • Cancelreply