Bootstrap

epoll编程实例客户端_Python epoll网络编程二:客户端模型

Python epoll网络编程二:客户端模型

第一篇简单介绍了一个使用epoll的服务器模型,本节介绍使用epoll的客户端模型,客户端连接多个服务器。

以下是发送hello请求的客户端,可以作为探测程序,探测服务器的工作状态,如果返回greeting,表示服务器正常工作。代码如下:

zip.gif文件:epoll_python.zip

大小:2KB

下载:

def usage():

print 'python epoll_client.py ::...'

print '\texample: python epoll_client.py localhost:9999 localhost:9998'

sys.exit(1)

class HelloClient(EpollConnector):

''' extends EpolloServer, overload do_operation'''

def __init__(self, logger, srvs):

EpollConnector.__init__(self, logger, srvs)

def parse_response(self, fileno):

if self.responses[fileno] != epoll_util.greeting_response:

try:

print 'error in response %s'%str(self.connections[fileno].getpeername())

except:

print 'disconnect'

if __name__ == "__main__":

srvs = []

for arg in sys.argv[1:]:

try:

a, p = arg.split(':')

srvs.append((a, int(p)))

except :

usage()

if len(srvs) == 0:

usage()

srv = HelloClient(None, srvs)

srv.init_epoll()

srv.loop_epoll()

EpollConnector.init_epoll():

epoll_connector.py

21    def init_epoll(self):

22        # fileno set for connection

23        self.conns_index = {}

24        self.connections = {}

25        self.requests = {}

26        self.responses = {}

27        for i in range( len( self.srvs_addr ) ):

28            try:

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

30                s.connect(self.srvs_addr[i])

31                s.setblocking(0)

32                fileno = s.fileno()

33                self.epoll.register(fileno, select.EPOLLOUT | select.EPOLLET)

34            except socket.error:

35                print 'ERROR in connect to %s'%str( self.srvs_addr[i] )

36                sys.exit(1)

37            else:

38                self.conns_index[fileno] = i

39                self.connections[fileno] = s

40                self.requests[fileno] = b''

41                self.responses[fileno] = b''

23-26行:初始化连接信息,key均为fileno; conns_index的value是客户连接编号; connections,requests,responses 的value分别是socket和请求与相应;

29-32行:初始化客户端连接,监听EPOLLOUT;与服务器模型相反,服务器模型初始化监听EPOLLIN;

34-36行:当连接失败时,退出;

38-41行:当连接成功,初始化连接的信息;

EpollConnector.loop_epoll():

epoll_connector.py

92    def loop_epoll(self):

93        try:

94            while self.status != epoll_util.close_status:

95                events = self.epoll.poll()

96                for fileno, event in events:

97                    self.do_epoll(fileno, event)

98        finally:

99            self.close_epoll()

92-99行:与服务器模型相同,处理监听事件;

EpollConnector.do_epoll():

epoll_connector.py

72    def do_epoll(self, fileno, event):

73        try:

74            if event & select.EPOLLOUT:

75                self.do_request(fileno)

76            elif event & select.EPOLLIN:

77                self.do_response(fileno)

78            elif event & select.EPOLLHUP:

79                self.hup_epoll(fileno)

80        except:

81            raise

74-75行:EPOLLOUT 可读时,调用do_request读取相应;

77-78行:EPOLLIN可读时,调用do_response读取相应;

request和response是针对连接请求而言,因此客户端与服务器段的监听事件与监听动作正好相反;

EpollConnector.do_request(self, fileno):

epoll_connector.py

83    def set_request(self, fileno):

84        self.requests[fileno] = epoll_util.hello_request

85

86    def do_request(self, fileno):

87        self.set_request(fileno)

88        epoll_util.send_epoll(self.connections[fileno], self.requests[fileno])

89        self.epoll.modify(fileno, select.EPOLLIN | select.EPOLLET)

90        self.requests[fileno] = b''

87行:调用set_request(fileno)

设置请求,具体的客户端可overload此函数;

EpollConnector.do_response(self, fileno):

epoll_connector.py

43    #overload

44    def parse_response(self, response):

45        if self.responses[fileno] == epoll_util.fail_response:

46            pass

47

48    def do_response(self, fileno):

49        self.responses[fileno] = b''

50        s = self.connections[fileno]

51        self.responses[fileno] += epoll_util.recv_epoll(s)

52        self.parse_response(fileno)

53        self.epoll.modify(fileno, select.EPOLLOUT | select.EPOLLET)

52行:调用parse_response(response)

处理请求相应,具体的客户端可overload此函数;

源代码如下:

1import socket

2import select

3import sys

4import epoll_util

5

6class EpollConnector:

7'''generic epoll connectors which connect to down stream server'''

8def __init__(self, logger, srvs):

9self.logger = logger

10self.srvs_addr = srvs

11#status

12self.status = epoll_util.begin_status

13

14# initial epoll fileno

15self.epoll = select.epoll()

16

17def set_epoll(self, poll):

18self.epoll.close()

19self.epoll = poll

20

21def init_epoll(self):

22# fileno set for connection

23self.conns_index = {}

24self.connections = {}

25self.requests = {}

26self.responses = {}

27for i in range( len( self.srvs_addr ) ):

28try:

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

30s.connect(self.srvs_addr[i])

31s.setblocking(0)

32fileno = s.fileno()

33self.epoll.register(fileno, select.EPOLLOUT | select.EPOLLET)

34except socket.error:

35print 'ERROR in connect to %s'%str( self.srvs_addr[i] )

36sys.exit(1)

37else:

38self.conns_index[fileno] = i

39self.connections[fileno] = s

40self.requests[fileno] = b''

41self.responses[fileno] = b''

42

43#overload

44def parse_response(self, response):

45if self.responses[fileno] == epoll_util.fail_response:

46pass

47

48def do_response(self, fileno):

49self.responses[fileno] = b''

50s = self.connections[fileno]

51self.responses[fileno] += epoll_util.recv_epoll(s)

52self.parse_response(fileno)

53self.epoll.modify(fileno, select.EPOLLOUT | select.EPOLLET)

54

55#overload

56def recover(self, fileno):

57print 'hup_epoll', fileno

58

59def hup_epoll(self, fileno):

60self.recover(fileno)

61self.epoll.unregister(fileno)

62self.connections[fileno].close()

63del self.connections[fileno]

64del self.requests[fileno]

65del self.responses[fileno]

66del self.conns_index[fileno]

67

68

69def close_epoll(self):

70self.epoll.close()

71

72def do_epoll(self, fileno, event):

73try:

74if event & select.EPOLLOUT:

75self.do_request(fileno)

76elif event & select.EPOLLIN:

77self.do_response(fileno)

78elif event & select.EPOLLHUP:

79self.hup_epoll(fileno)

80except:

81raise

82

83def set_request(self, fileno):

84self.requests[fileno] = epoll_util.hello_request

85

86def do_request(self, fileno):

87self.set_request(fileno)

88epoll_util.send_epoll(self.connections[fileno], self.requests[fileno])

89self.epoll.modify(fileno, select.EPOLLIN | select.EPOLLET)

90self.requests[fileno] = b''

91

92def loop_epoll(self):

93try:

94while self.status != epoll_util.close_status:

95events = self.epoll.poll()

96for fileno, event in events:

97self.do_epoll(fileno, event)

98finally:

99self.close_epoll()

100

101

102def usage():

103print 'python epoll_client.py ::...'

104print '\texample: python epoll_client.py 218.241.108.68:9999 218.241.108.68:9998'

105sys.exit(2)

106

107

108class HelloClient(EpollConnector):

109''' extends EpolloServer, overload do_operation'''

110def __init__(self, logger, srvs):

111EpollConnector.__init__(self, logger, srvs)

112

113def parse_response(self, fileno):

114if self.responses[fileno] != epoll_util.greeting_response:

115try:

116print 'error in response %s'%str(self.connections[fileno].getpeername())

117except:

118print 'disconnect'

119

120

121if __name__ == "__main__":

122srvs = []

123for arg in sys.argv[1:]:

124try:

125a, p = arg.split(':')

126srvs.append((a, int(p)))

127except :

128usage()

129if len(srvs) == 0:

130usage()

131srv = HelloClient(None, srvs)

132srv.init_epoll()

133srv.loop_epoll()

;