-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathclient.py
More file actions
147 lines (119 loc) · 3.15 KB
/
client.py
File metadata and controls
147 lines (119 loc) · 3.15 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/python
# -*- coding=utf-8 -*-
__author__ = ['"wuyadong" <wuyadong311521@gmail.com>']
import time
import socket
from errno import EWOULDBLOCK, ECONNRESET, \
ENOTCONN, ESHUTDOWN, ECONNABORTED
import logging
from util import except_info
class ClientException(Exception):
"""client error
"""
class CloseClientException(Exception):
"""fake exception, close
"""
class Client(object):
READ_BUFFER_SIZE = (1 << 12) # 4kb
MAX_READ_BUFFER_SIZE = (1 << 16) # 16kb
WRITE_BUFFER_SIZE = (1 << 18) # 256kb
IDLE_TIMEOUT = 60 * 5 # 5 minutes
def __init__(self, socket):
self.socket = socket
self.address = socket.getpeername()
self.read_buffer = ""
self.write_buffer = ""
self.running = True
self.last_activity = time.time()
self.init()
self.logger = logging.getLogger()
self.logger.info("%s:%s - Connection" % (self.address[0], self.address[1]))
def read(self):
"""
:return:
"""
if self.running and (self.socket is not None):
try:
data = self.socket.recv(self.READ_BUFFER_SIZE)
if not data:
self.running = False
self.socket.shutdown(socket.SHUT_RDWR)
raise CloseClientException("read, but empty data")
except socket.error, e:
if e.args[0] in (ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED):
self.running = False
self.socket.shutdown(socket.SHUT_RDWR)
raise ClientException("socket read error:%s" % except_info())
else:
raise
self.read_buffer += data
if len(self.read_buffer) > self.MAX_READ_BUFFER_SIZE:
raise ClientException("Maxread buffer size reached")
def write(self):
"""
:return:
"""
if self.running and (self.socket is not None) and (len(self.write_buffer) > 0):
try:
result = self.socket.send(self.write_buffer)
except socket.error, e:
if e.args[0] == EWOULDBLOCK:
return
elif e.args[0] in (ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED):
self.running = False
self.socket.shutdown(socket.SHUT_RDWR)
else:
raise
else:
print result, self.write_buffer
self.write_buffer = self.write_buffer[result:]
self.last_activity = time.time()
def close(self):
try:
self.socket.close()
except:
pass
self.socket = None
self.read_buffer = ""
self.write_buffer = ""
self.running = False
def process(self):
if not self.running:
return
if (time.time() - self.last_activity) > Client.IDLE_TIMEOUT:
return
if len(self.read_buffer) > 0:
pos = 0
length = len(self.read_buffer)
while length > 0:
message = self.readMessage(buffer(self.read_buffer, pos))
if message is None:
break
else:
pos += message[0]
length -= message[0]
if message[1] is not None:
self.processMessage(message[1])
if pos > 0:
self.read_buffer = self.read_buffer[pos:]
self.last_activity = time.time()
def writeMessage(self, data):
if data is not None:
self.write_buffer += data
def readMessage(self, message):
"""read message
:param message:
:return:
"""
raise NotImplementedError
def processMessage(self, message):
"""process message
:param message:
:return:
"""
raise NotImplementedError
def init(self):
"""init
:return:
"""
raise NotImplementedError