**Assignment 12: Networking** # Learning Goals - Learn how to write networked programs. - Gain experience with TCP sockets. # Grading Walk-Throughs This assignment will be graded as "Nailed It" / "Not Yet" by a TA. To pass ("Nailed It") the assignment, you must 1. Complete the assignment and submit your work to gradescope. + You should start this assignment in class on the day shown on the calendar. + *Complete the assignment as early as possible*. 1. Schedule a time to meet with a TA. You can meet with them after the submission deadline. + You must book a time to meet with a TA + Sign-up on the Google Sheet *with at least 36 hours of notice*. + Contact your TA on Slack after signing up. + All partners must meet with the TA. If you cannot all make it at the same time, then each of you needs to schedule a time to meet with the TAs. 1. Walk the TA through your solutions prior to the deadline. + Walk-throughs should take no more than 20 minutes. + You should be well prepared to walk a TA through your answers. + You may not make any significant corrections during the walk-through. You should plan on making corrections afterward and scheduling a new walk-through time. Mistakes are expected---nobody is perfect. + You must be prepared to explain your answers and justify your assumptions. TAs do not need to lead you to the correct answer during a walk-through---this is best left to a mentor session. 1. The TA will then either + mark your assignment as "Nailed It" on gradescope, or + mark your assignment as "Not Yet" and inform you that you have some corrections to make. 1. If corrections are needed, then you will need to complete them and then schedule a new time to meet with the TA. + You will ideally complete any needed revisions by the end of the day the following Monday. If you have concerns about the grading walk-through, you can meet with me after you have first met with a TA. # Overview For this assignment, you will implement a simple client-server messaging system that will send messages back and forth over the network (really just to and from different users on the same server). You should complete this assignment with a partner. Let me know if you want help finding one! Starter code is available on the server: ~~~bash tar xvf /data/A12-Networking.tar ~~~ You'll find the following files in the archive: `imclient.c`, `imserver.c`, and `Makefile`. **Only one process can be "bound" to a given port at a time. To handle contention (where multiple processes want to use the same port) you will each be assigned a port.** You can find the list of ports in the Port Numbers section. Both the client and server will run on the server. The server is setup such that you will not be able to communicate with other machines, but two users can communicate with each other. For example, one partner can run the server and the second can run the client. One final note: each `TODO` found in the starter code will require you to change the subsequent line of code. For example, the first `TODO` is: ~~~c // TODO: call socket with the correct parameters int listenfd = 0; ~~~ and you will change this to ~~~c // TODO: call socket with the correct parameters int listenfd = socket(PF_INET, SOCKET_TYPE, 0); ~~~ # TCP Sockets The socket interface implements standards for "low-level" networked programs. Programs that work with TCP sockets all follow the same pattern. First, the server opens a socket and binds it socket to its IP address (or one of its IP addresses, if the computer has multiple NICs) and to some specified port number. Many of the lower port numbers are reserved for particular types of applications (and might already be in use). For your own work, I'd recommend that you bind to a port number above 8000; you have been assigned a port for this assignment. The server then listens for incoming connections. Accepting an incoming connection opens a **new** socket file descriptor, which is then used to read and write over the TCP connection. When the client starts up, it opens a socket and connects to the server using the server IP address and the port associated with the listening socket. It then reads and writes to the server using this socket. This design pattern is summarized in the diagram below. ![](TCPDiagram.svg) Note: the following descriptions are not complete, they are just intended to give you some hints for getting started. You will probably find yourself needing to look at the full socket documentation. One amazing resources is [Beej's Guide to Network Programming](https://beej.us/guide/bgnet/html/). ## Opening a Socket To open a socket, you need to specify the *type* of IP address you will use (i.e., IPv4 or IPv6) and the type of protocol you will use (i.e., TCP or UDP). The value for IPv4 addresses is `AF_INET` and the value for TCP sockets is `SOCK_STREAM`. In C, this looks like ~~~c int socket(int domain, int type, int protocol); ~~~ [Manual for `socket`](https://man7.org/linux/man-pages/man2/socket.2.html). ## Binding a Socket Before you can use a socket, you need to bind it to an IP address and a port. It is good practice to not hard-code the IP address of your computer (as this will likely change!) and instead use an IP address currently assigned to that computer. The signature for the bind function is ~~~c int bind(int sockfd, const struct sockaddr * addr, socklen_t addrlen); ~~~ [Manual for `bind`](https://man7.org/linux/man-pages/man2/bind.2.html). Hint: Networking tends to use big-endian numbers. You will need to explicitly convert your IP addresses/ports into network order. You might want to investigate the functions `htons`, `htonl`, and `inet_addr`. ## Listening for a Connection The signature for the listen function is ~~~c int listen(int sockfd, int backlog); ~~~ [Manual for `listen`](https://man7.org/linux/man-pages/man2/listen.2.html). ## Accepting a Connection The signature for the accept function is ~~~c int accept(int sockfd, struct sockaddr * addr, socklent_t * addrlen); ~~~ [Manual for `accept`](https://man7.org/linux/man-pages/man2/accept.2.html). ## Initiating a Connection The client initiates a TCP connection using the connect function. The signature for this function is ~~~c int connect(int sockfd, const struct sockaddr * addr, socklen_t addrlen); ~~~ [Manual for `connect`](https://man7.org/linux/man-pages/man2/connect.2.html). ## Reading and Writing to a Socket Given a connected TCP socket file descriptor, you can read and write to the network just the same as you would read and write to a file! In C, the UNIX IO functions are `read` and `write`. For this assignment, however, I am asking you to use `recv` and `send`, which provide a bit more control and flexibility. For one thing, the `recv` command has a way of letting you know when the other side closes the connection. ~~~c ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t send(int sockfd, const void *buf, size_t len, int flags); ~~~ Manuals for [`recv`](https://man7.org/linux/man-pages/man2/recv.2.html) and [`send`](https://man7.org/linux/man-pages/man2/send.2.html). ## Closing a Socket It is good form to close your socket when they are no longer needed. ~~~c int close(int fd); ~~~ [Manual for `close`](https://man7.org/linux/man-pages/man2/close.2.html). # Tasks Your tasks are to implement a client and a server that exchange messages over the network. You will use TCP sockets to implement this task; a summary of the TCP socket life-cycle, along with descriptions of the relevant functions, is given in section TCP Sockets. ## Task 1: The Server Let's start with the server side. The server will take one program argument: a port number. If you pass in `0`, the program will let the operating system assign a random port. On startup, the server will 1. gather information about itself (`getaddrinfo`), 2. open a socket (`socket`), 3. bind the socket to the given port (and the computer's IP address) (`bind`), 4. listen for incoming connections (`listen`), and 5. accept a client connection when one is made (`accept`). After connecting to a client it will enter a chat loop in which it 1. waits for a message from the client (`recv`), 2. prints the message to `stdout`, 3. reads a line from `stdin`, and then 4. sends that response to the client (`send`). When the client closes the connection, the server will close its open sockets with `close`. ### Demo When your server is completed, you can test it with the `nc` (network concatenate command). You'll notice that I made a few mistakes below, and that this was assignment 11 in the past. If you do not see an animation above this line (or if you see the animation but you don't see the progress bar), you will need to refresh the page (sometimes more than once). Or you can go directly to the player: https://asciinema.org/a/491106 ## Task 2: The Client The client will take two program arguments: the IP address and port number of the server. Since we are running the server and client on the server, you should [use `localhost` for the server's IP address](https://en.wikipedia.org/wiki/Localhost) (you could also type `127.0.0.1`). The client will 1. gather information about the server (`getaddrinfo`), 2. open a socket (`socket`), and then 3. initiate a TCP connection with the server (`connect`). Once a connection has been established, the client will enter a chat loop in which it 1. reads a line from `stdin`, 2. sends the message to the server (`send`), 3. waits for a response from the server (`recv`), and then 4. prints that response to `stdout`. If the line read from `stdin` is `"bye\n"`, then the client will break the loop and close its socket (`close`). This should signal to the server that it should shut down. ### Demo A sample interaction between client and server shown below. To test your client you will need to have a server running. You can do so using one of the following options: 1. Have one partner start the server and then the second partner start the client. 1. Open two separate terminal windows, log both into the server, and then start the server in one window and the client in the other window. 1. Use [tmux](https://tmuxcheatsheet.com/) as I do in the demo. **I don't recommend using tmux unless you have some idea of what you are doing, including how and when to kill a tmux session.** If you do not see an animation above this line (or if you see the animation but you don't see the progress bar), you will need to refresh the page (sometimes more than once). Or you can go directly to the player: https://asciinema.org/a/491107 # Port Numbers Partners can use whichever port they'd like. Name | Port -----|----- ToCh | 8932 NaDa | 8934 MeFe | 8936 KeGH | 8938 AnGu | 8940 EvHa | 8942 ViHB | 8944 RaHo | 8946 RiIm | 8948 SaJa | 8950 LiJo | 8952 SaKh | 8954 JuKi | 8956 CoKi | 8958 GlLe | 8960 KaLe | 8962 EsLu | 8964 MaLy | 8966 MaNi | 8968 MaPo | 8970 SaRi | 8972 SoRi | 8974 MeWa | 8976 JaWe | 8978 JiWu | 8980 DaYa | 8982 RaYa | 8984 JoYu | 8986 # Submitting Your Assignment You will submit your code and/or responses on gradescope. **Only one partner should submit.** The submitter will add the other partner through the gradescope interface. To pass the autograder (if one exists for this assignment), your output must exactly match the expected output. Your program output should be similar to the example execution above, and the autograder on gradescope will show you the correct output if yours is not formatted properly. You can use [text-compare](https://text-compare.com/) to compare your output to the expected output and that should give you an idea if you have a misspelled word or extra space (or if I do). Additional details for using gradescope can be found here: - [Submitting an Assignment](https://help.gradescope.com/article/ccbpppziu9-student-submit-work) - [Adding Group Members](https://help.gradescope.com/article/m5qz2xsnjy-student-add-group-members) - [gradescope Student Help Center](https://help.gradescope.com/category/cyk4ij2dwi-student-workflow)