forked from marcelomd/mux_serial
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmux_server.py
executable file
·181 lines (149 loc) · 4.59 KB
/
mux_server.py
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#! /usr/bin/env python
# vim:noexpandtab:
import sys, os, errno
import select, socket, serial
_default_host = 'localhost'
_default_port = 23200
_default_device = '/dev/ttyS0'
_default_baudrate = 9600
_default_width = serial.EIGHTBITS
_default_parity = serial.PARITY_NONE
_default_stopbits = serial.STOPBITS_ONE
_default_xon = 0
_default_rtc = 0
_READ_ONLY = select.POLLIN | select.POLLPRI
class MuxServer(object):
def __init__(self,
host=_default_host,
port=_default_port,
device = _default_device,
baudrate=_default_baudrate,
width = _default_width,
parity = _default_parity,
stopbits = _default_stopbits,
xon = _default_xon,
rtc = _default_rtc,):
self.host = host
self.port = port
self.device = device
self.baudrate = baudrate
self.width = width
self.parity = parity
self.stopbits = stopbits
self.xon = xon
self.rtc = rtc
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.setblocking(0)
# do not wait for TIME_WAIT old socket if we restart server quickly
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.poller = select.poll()
self.fd_to_socket = {}
self.clients = []
def close(self):
print >>sys.stderr, '\nMUX > Closing...'
for client in self.clients:
client.close()
self.tty.close()
self.server.close()
print >>sys.stderr, 'MUX > Done! =)'
def add_client(self, client):
print >>sys.stderr, 'MUX > New connection from', client.getpeername()
client.setblocking(0)
self.fd_to_socket[client.fileno()] = client
self.clients.append(client)
self.poller.register(client, _READ_ONLY)
def remove_client(self, client, why='?'):
try:
name = client.getpeername()
except:
name = 'client %d' % client.fileno()
print >>sys.stderr, 'MUX > Closing %s: %s' % (name, why)
self.poller.unregister(client)
self.clients.remove(client)
client.close()
def run(self):
try:
self.tty = serial.Serial(self.device, self.baudrate,
self.width, self.parity, self.stopbits,
1, self.xon, self.rtc)
self.tty.timeout=0 # Non-blocking
self.tty.flushInput()
self.tty.flushOutput()
self.poller.register(self.tty, _READ_ONLY)
self.fd_to_socket[self.tty.fileno()] = self.tty
print >>sys.stderr, 'MUX > Serial port: %s @ %s' % (self.device, self.baudrate)
self.server.bind((self.host, self.port))
self.server.listen(5)
self.poller.register(self.server, _READ_ONLY)
self.fd_to_socket[self.server.fileno()] = self.server
print >>sys.stderr, 'MUX > Server: %s:%d' % self.server.getsockname()
print >>sys.stderr, 'MUX > Use ctrl+c to stop...\n'
while True:
events = self.poller.poll(500)
for fd, flag in events:
# Get socket from fd
s = self.fd_to_socket[fd]
if flag & select.POLLHUP:
self.remove_client(s, 'HUP')
elif flag & select.POLLERR:
self.remove_client(s, 'Received error')
elif flag & (_READ_ONLY):
# A readable server socket is ready to accept a connection
if s is self.server:
connection, client_address = s.accept()
self.add_client(connection)
# Data from serial port
elif s is self.tty:
data = s.read(80)
for client in self.clients:
try:
client.send(data)
except socket.error, e:
# if the client goes away we do not care much
if e[0] == errno.EPIPE:
pass
print >>sys.stderr, '\nMUX > SIGPIPE ignore'
# unknown errors we send up the chain
else:
raise
# Data from client
else:
data = s.recv(80)
# Client has data
if data: self.tty.write(data)
# Interpret empty result as closed connection
else: self.remove_client(s, 'Got no data')
except serial.SerialException, e:
print >>sys.stderr, '\nMUX > Serial error: "%s". Closing...' % e
except socket.error, e:
print >>sys.stderr, '\nMUX > Socket error: %s' % e.strerror
except (KeyboardInterrupt, SystemExit):
pass
finally:
self.close()
if __name__ == '__main__':
import optparse
# Option parsing, duh
parser = optparse.OptionParser()
parser.add_option('-d',
'--device',
help = 'Serial port device',
dest = 'device',
default = _default_device)
parser.add_option('-b',
'--baud',
help = 'Baud rate',
dest = 'baudrate',
type = 'int',
default = _default_baudrate)
parser.add_option('-p',
'--port',
help = 'Host port',
dest = 'port',
type = 'int',
default = _default_port)
(opts, args) = parser.parse_args()
s = MuxServer(port = opts.port,
device = opts.device,
baudrate = opts.baudrate)
s.run()