LMU ☀️ CMSI 355
COMPUTER NETWORKS
HOMEWORK #1 PARTIAL ANSWERS

Short Answer Problems

  1. Cerf and Kahn’s 1974 paper, A Protocol for Packet Network Intercommunication. This paper was massively influential as it introduced what may have been the first cross-network protocol (a protocol allowing different networks to communicate with each other), enabling a truly world-wide computer network.
  2. Circuit switching in a network creates a dedicated path between the communicating hosts for a session. So all communication passes through the same intermediate points. Packet switching breaks up messages into packets and routes them dynamically from end to end. Packets in the same message may take different paths.
  3. According to Wikipedia, the Internet Engineering Task Force (IETF), the Internet Research Task Force (IRTF), the Internet Architecture Board (IAB), and independent authors are all sources of RFCs. The RFC system is supported by the Internet Society (ISOC). The IETF is the body that can accept an RFC as an Internet standard.
  4. netstat -r
  5. The transport layer ensures data sent by an application is delivered to the correct application on the other end. This layer has knowledge not only of the Internet address but also the port number of the communicating hosts. On the sending side, the transport layer asks the network layer to deliver the packets (segments) to the receiving host. On the receiver, the transport layer passes the segments up to the application layer. Some protocols within the transport layer, like TCP, ensure reliable delivery (asking for retransmission and reassembling in order to provide a stream view to the application layer); other protocols, like UDP, do not.
  6. First message was 'L' and second was 'O'.
  7. TCP is reliable while UDP is not. TCP supports flow and congestion control, assembly of out of order packets, retransmission requests, and connection set up and tear down. UDP does not of those things.
  8. 20 bytes
  9. 60 bytes
  10. Node.js servers are event-driven and use a single thread for event handling.

Scripts

Random Number Server and Client

random_number_server.py
import socketserver
import random

class RandomHandler(socketserver.StreamRequestHandler):
    def handle(self):
        self.wfile.write(f'{random.randint(1, 1000)}\n'.encode('utf-8'))

with socketserver.TCPServer(('', 53211), RandomHandler) as server:
    print('The random number server is running...')
    server.serve_forever()
random_number_client.py
import sys
import socket

if len(sys.argv) != 2:
    print('Pass the server IP as the sole command line argument')
else:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect((sys.argv[1], 53211))
        print(sock.recv(1024).decode('utf-8'))

Echo Server and Client

echo_server.py
import socketserver
import threading

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    daemon_threads = True
    allow_reuse_address = True

class EchoHandler(socketserver.StreamRequestHandler):
    def handle(self):
        client = f'{self.client_address} on {threading.currentThread().getName()}'
        print(f'Connected: {client}')
        while True:
            data = self.rfile.readline()
            if not data:
                break
            self.wfile.write(data)
        print(f'Closed: {client}')

with ThreadedTCPServer(('', 43210), EchoHandler) as server:
    print(f'The echo server is running...')
    server.serve_forever()
echo_client.py
import sys
import socket

if len(sys.argv) != 2:
    print('Pass the server IP as the sole command line argument')
else:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect((sys.argv[1], 43210))
        print('Enter lines of text then Ctrl+D or Ctrl+C to quit')
        while True:
            line = sys.stdin.readline()
            if not line:
                # End of standard input, exit this entire script
                break
            sock.sendall(f'{line}'.encode('utf-8'))
            while True:
                data = sock.recv(128)
                print(data.decode("utf-8"), end='')
                if len(data) < 128:
                    # No more of this message, go back to waiting for next message
                    break

Chat Server

chat_server.py
import socketserver
import threading

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    daemon_threads = True
    allow_reuse_address = True

names = set()
writers = set()

class ChatHandler(socketserver.StreamRequestHandler):
    def handle(self):
        client = f'{self.client_address} on {threading.currentThread().getName()}'
        try:
            while True:
                self.wfile.write(f'SUBMITNAME\n'.encode('utf-8'))
                name = self.rfile.readline().decode('utf-8').strip()
                if name == "":
                    return
                with threading.Lock():
                    if name != "" and name not in names:
                        names.add(name)
                        break

            self.wfile.write(f'NAMEACCEPTED: {name}\n'.encode('utf-8'))
            for w in writers:
                w.write(f'MESSAGE {name} has joined\n'.encode('utf-8'))
            writers.add(self.wfile)

            while True:
                message = self.rfile.readline().decode('utf-8')
                if message.lower().startswith('/quit'):
                    return
                for w in writers:
                    w.write(f'MESSAGE {name}: {message}\n'.encode('utf-8'))
        except Exception as e:
            print(e)
        finally:
            if self.wfile is not None:
                writers.remove(self.wfile)
            if name is not None:
                names.remove(name)
                for w in writers:
                    w.write(f'MESSAGE {name} has left\n'.encode('utf-8'))

if __name__ == '__main__':
    with ThreadedTCPServer(('', 59001), ChatHandler) as server:
        print(f'The chat server is running...')
        server.serve_forever()