generated from kevinawalsh/csci356-p4-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.py
executable file
·104 lines (88 loc) · 3.71 KB
/
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
#!/usr/bin/env python3
#
# Author: K. Walsh <[email protected]>
# Date: 4 April 2017
#
# Server for a simple TCP-like semi-reliable protocol on top of UDP.
#
# What it does: This version expects the first 8 bytes of each packet to contain
# a sequence number and a magic number. The magic number is completely ignored.
# Every time a packet arrives, an 8-byte ACK is sent back, consisting of the
# magic number 0xAAAAAAAA followed by the sequence number just received.
#
# What it doesn't do: There is no real attempt to detect missing packets, send
# NACKs, use cumulative acknowledgements, or do any sort of flow-control. The
# code in datasink.py will keep track of duplicates and rearrange mis-ordered
# packets, so we don't need to worry about that here.
#
# Run the program like this:
# python3 server.py 1.2.3.4 6000
# This will listen for data on UDP 1.2.3.4:6000. The IP address should be the IP
# for our own host.
import socket
import sys
import time
import struct
import datasink
import trace
# setting verbose = 0 turns off most printing
# setting verbose = 1 turns on a little bit of printing
# setting verbose = 2 turns on a lot of printing
# setting verbose = 3 turns on all printing
verbose = datasink.verbose = 2
# setting tracefile = None disables writing a trace file for the server
# tracefile = None
tracefile = "server_packets.csv"
def main(host, port):
print("Listening for UDP packets at %s:%d" % (host, port))
server_addr = ("", port)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Makes a UDP socket!
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(server_addr)
trace.init(tracefile,
"Log of all packets received by server",
"SeqNo", "TimeArrived", "NumTimesSeen")
datasink.init(host)
start = time.time()
lowest_seqno = 0
backlog = {}
while True:
# wait for a packet, and record the time it arrived
(packet, client_addr) = s.recvfrom(4000)
tRecv = time.time()
# split the packet into header (first 8 bytes) and payload (the rest)
hdr = packet[0:8]
payload = packet[8:]
# unpack integers from the header
(magic, seqno) = struct.unpack(">II", hdr)
# if this packet is what we're waiting for, pass it on
if seqno == lowest_seqno:
numTimesSeen = datasink.deliver(seqno, payload)
# see if we already have the new packet we're now waiting for
lowest_seqno += 1
while lowest_seqno in backlog:
numTimesSeen = datasink.deliver(lowest_seqno, backlog[lowest_seqno])
backlog.pop(lowest_seqno) # Remove it once in data sink
lowest_seqno += 1
# otherwise, save it for later (reordering)
else:
backlog[seqno] = payload
if verbose >= 2:
print("Got a packet containing %d bytes from %s" % (len(packet), str(client_addr)))
print(" packet had magic = 0x%08x and seqno = %d" % (magic, seqno))
print(" packet has been seen %d times, including this time" % (numTimesSeen))
# write info about the packet to the log file
trace.write(seqno, tRecv - start, numTimesSeen)
# create and send an ACK
if verbose >= 2:
print(" sending ACK in reply containing seqno = %d" % (seqno))
ack = bytearray(struct.pack(">II", 0xAAAAAAAA, seqno))
s.sendto(ack, client_addr)
if __name__ == "__main__":
if len(sys.argv) <= 2:
print("To listen for data on IP address 1.2.3.4 UDP port 6000, try running:")
print(" python3 server.py 1.2.3.4 6000")
sys.exit(0)
host = sys.argv[1]
port = int(sys.argv[2])
main(host, port)