1. How does the remote client determine when a command's output is fully received from the server, and what techniques can be used to handle partial reads or ensure complete message transmission? _answer here_ > Loop Until EOF Character is Received > - The client continuously reads from the socket using `recv()`, checking if the last byte received is `0x04` (EOF). > - If the EOF character is detected, the client knows the full response has been received. > Buffering and Aggregation > Since `recv()` may return partial data, the client should append data to a buffer until the EOF character is found. 2. This week's lecture on TCP explains that it is a reliable stream protocol rather than a message-oriented one. Since TCP does not preserve message boundaries, how should a networked shell protocol define and detect the beginning and end of a command sent over a TCP connection? What challenges arise if this is not handled correctly? _answer here_ > Use a Terminator Character > - The protocol can use a special delimiter, such as `\0`(null byte) for commands and `0x04` (EOF) for responses. > Include Message Length in the Header > - A fixed-size header can precede each message, specifying the number of bytes in the payload. > Use a Structured Format (e.g., JSON, XML) > - While not ideal for simple shell protocols, structured formats like JSON allow parsing with defined message start and end markers. > Chanllenges: > - TCP might split a message across multiple `recv()` calls, requiring the client to reconstruct it. > - TCP might merge multiple commands into one `recv()` call, requiring the client to parse multiple messages properly. > - If no end delimiter is used, the client may read incomplete commands, leading to unexpected behavior. 3. Describe the general differences between stateful and stateless protocols. _answer here_ > A stateful protocol maintains session state between client and server across multiple interactions, whereas a stateless protocol treats each request as independent with no retained memory of past interactions. > Stateful Protocols: > The server remembers previous interactions. Requires more server-side resources (e.g., memory, session tracking). > Examples: > - TCP (tracks sequence numbers, retransmissions). > - SSH (maintains authentication state). > - HTTP with Sessions (stores login cookies). > Stateless Protocols: > Each request is independent; no session state is stored. Easier to scale since no session tracking is needed. > Examples: > - UDP (each packet is independent). > - HTTP (by default, unless cookies or tokens are used). > - DNS (each lookup request is processed independently). 4. Our lecture this week stated that UDP is "unreliable". If that is the case, why would we ever use it? _answer here_ > Although UDP is unreliable, which does not guarantee packet delivery, order, or integrity, it is still useful for applications where speed and low latency are more important than reliability. > Since there is no connection setup or retransmission, UDP is much faster than TCP, which lower the latency. > UDP allows sending packets to multiple recipients simultaneously, which is crucial for Streaming video/audio, Online gaming (real-time updates), IoT devices (sensor updates) > DNS uses UDP because queries are small and fast (retrying is faster than using TCP). 5. What interface/abstraction is provided by the operating system to enable applications to use network communications? _answer here_ > The operating system provides socket APIs that allow applications to communicate over a network using protocols like TCP and UDP. > Example: > Berkeley Sockets API (socket.h) > Standard API used in C, C++, Python, etc. for network communication. > > Functions: > - `socket()` → Creates a socket. > - `bind()` → Binds a socket to an IP/port. > - `listen()` → Marks a socket for incoming connections. > - `accept()` → Accepts a new client connection. > - `connect()` → Connects to a remote server. > - `send()`/`recv()` → Sends & receives data.