server_udp_or_tcp.py
5.33 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
148
149
#!/usr/bin/env python3
# cf https://docs.python.org/3/library/socketserver.html#socketserver-tcpserver-example
"""Socket Server implementation
To be used as a minimalist telescope simulator to which a socket client (SocketClient) can connect
"""
# Standard library imports
import socketserver
# Third party imports
# None
# Local application imports
# None
# Default very BASIC implementation - to be overriden by subclass
def make_answer_for_request(request_bytes):
#raise NotImplementedError
print("Request received is", request_bytes)
# Convert to string
request = request_bytes.decode("utf-8")
#if len(request) < STAMP_LENGTH+2+1: raise UnknownCommandException(request)
# Remove TERMINATOR
#request = request[0:-1]
# Remove leading stamp
#stamp = request[0:STAMP_LENGTH]
#command = request[STAMP_LENGTH:]
command = request
print("Command received is", repr(command))
answer = 'ANSWER TO '+command.upper()
#if command == ':GR#': answer = "15:01:49"
#elif command == ':GD#': answer = "+12:29"
#elif command == ':SG+00#': answer = "1"
#elif command == ':GG#': answer = "+00"
#full_answer_in_bytes = bytes(stamp + answer + '#' + TERMINATOR, "utf-8")
full_answer_in_bytes = bytes(answer, "utf-8")
#print("request str upper is", str(request).upper())
print("Answer sent is", full_answer_in_bytes)
return full_answer_in_bytes
def get_SocketServer_UDP_TCP(myhost:str="localhost", myport:int=11110, PROTOCOL:str="TCP", func_make_answer_for_request=make_answer_for_request):
socketserver_type = socketserver.UDPServer if PROTOCOL=="UDP" else socketserver.TCPServer
socketserver_handler_type = socketserver.DatagramRequestHandler if PROTOCOL=="UDP" else socketserver.StreamRequestHandler
"""
A classic version of request handler:
"""
class _MyUDPorTCPHandler_classic(socketserver.BaseRequestHandler):
# The request handler class for our server.
# It is instantiated once per connection to the server, and must
# override the handle() method to implement communication to the client
def handle(self):
# Get received data
# - TCP
if PROTOCOL == "TCP":
# For TCP, self.request is the TCP socket connected to the client
data_rcv = self.request.recv(1024).strip()
# - UDP
else:
# For UDP, self.request consists of a pair of data and client socket
data_rcv = self.request[0].strip()
socket_client = self.request[1]
print("{} wrote:".format(self.client_address[0]))
print(data_rcv)
# Send back the same data, but upper-cased
# - TCP
if PROTOCOL == "TCP":
self.request.sendall(data_rcv.upper())
# - UDP
# Since there is no connection, the client address must be given explicitly when sending data back via sendto().
else:
socket_client.sendto(data_rcv.upper(), self.client_address)
"""
An alternative request handler class that makes use of streams
(file-like objects that simplify communication by providing the standard file interface):
"""
#class MyTCPHandler(socketserver.StreamRequestHandler):
#class MyUDPHandler(socketserver.DatagramRequestHandler):
class _MyUDPorTCPHandler(socketserver_handler_type):
def get_useful_data(self, data_received):
return data_received
'''
def make_answer_for_request(self, request_bytes:bytes):
##return self.make_answer_for_request_Gemini(request_bytes)
raise NotImplementedError
'''
# @override
def handle(self):
# 1) RECEIVE REQUEST from client
# self.rfile is a file-like object created by the handler;
# we can now use e.g. readline() instead of raw recv() calls
data_received = self.rfile.readline().strip() # data is "bytes" type
data_useful = self.get_useful_data(data_received)
#print("data type is", type(data))
#print("\nFrom {}, received: {}".format(self.client_address[0], data_useful))
print(f"\nFrom {self.client_address[0]}, received: {data_useful}")
# 2) SEND REPLY to client
# Likewise, self.wfile is a file-like object used to write back to the client
#self.wfile.write(self.make_answer_for_request(data_useful))
self.wfile.write(func_make_answer_for_request(data_useful))
# inutile, ca plante car data est deja en bytes:
#self.wfile.write(data.upper().encode())
# Return a "classic" handler:
#return socketserver_type((HOST, PORT), _MyUDPorTCPHandler_classic)
# or a more "modern" handler:
return socketserver_type((myhost, myport), _MyUDPorTCPHandler)
if __name__ == "__main__":
#with socketserver_type((HOST, PORT), MyUDPorTCPHandler_classic) as myserver:
'''
with socketserver_type((HOST, PORT), MyUDPorTCPHandler) as myserver:
myserver.serve_forever()
'''
#with get_SocketServer_UDP_TCP("localhost", 11110, "UDP", make_answer_for_request) as myserver:
with get_SocketServer_UDP_TCP("localhost", 11110, "UDP") as myserver:
myserver.serve_forever()