Sockets are a method of IPC that allow data to be exchanged between applications, either on the same host (computer) or on different hosts connected by a network.
—Michael Kerrisk, The Linux Programming Interface, Chapter 56, pp. 1149.
Sockets provide efficient ways to do file-like input and output between processes on the same host, or on different hosts. Their biggest benefit is that they allow bi-directional communication as well as the ability to treat the endpoints as formatted input and output streams, just like you would read and write from files, or from streams like standard input and output.
In this studio, you will:
Please complete the required exercises below. We encourage you to please work in groups of 2 or 3 people on each studio (and the groups are allowed to change from studio to studio) though if you would prefer to complete any studio by yourself that is allowed.
As you work through these exercises, please record your answers, and when finished upload them along with the relevant source code to the appropriate spot on Canvas. If you work in a group with other people, only one of you should please upload the answers (and any other files requested) for the studio, and if you need to resubmit (e.g., if a studio were to be marked incomplete when we grade it) the same person who submitted the studio originally should please do that.
Make sure that the name of each person who worked on these exercises is listed in the first answer, and make sure you number each of your responses so it is easy to match your responses with each exercise.
man 2 bindunder the section labeled EXAMPLE.
Your server should perform the following actions:
socket()system call. To create a local connection use the domain
AF_UNIX), the connection type
SOCK_STREAM, and protocol zero.
bind()system call. This associates your socket from step one with a machine-visible address. In the case of
AF_LOCAL, this address is a path in the file system, and your local server program should use the first argument passed to it as a string containing that path. Directions on how to specify a local address in this way (and which header files you'll need in order to make that work) can be found at
man 7 unix, and there is a good example showing how to do this on page 1166 of the LPI (Kerrisk) text book.
listen()system call. Sockets only allow one process to connect at a time, so the second parameter determines how many connection requests can wait (queue up) before subsequent ones are rejected.
accept()system call to accept a connection over the socket interface, passing in NULL and NULL for the second and third arguments. If no connection is immediately available then this system call will, by default, cause your program to block until another program attempts to connect. When your program successfully returns from the call to
accept()the new communication socket connection has been established, and the return value from the call is a file descriptor for the new socket.
fdopenfunction and then using
fscanf(). When creating the stream, be sure to use the socket descriptor that was returned by the call to
accept()(the communication endpoint), not the one created by the initial call to
socket()(the connection establishment endpoint). As long as the communication endpoint socket remains open, the server should print out all unsigned integers that it receives, to its standard output stream.
unlink()system call in order to destroy the original local socket (connection establishment endpoint) file before the program returns.
Note: Many things can go wrong with socket-based
communication. As usual, you should always check function
return codes to detect errors. Recall that most functions
return error codes that allow you to print a descriptive error
statement with a line of code such as:
printf("Program error, reason: %s\n", strerror(errno)).
This will require including the headers
Now you will write a client program that should do the following:
connect()system call. This requires using the same local socket address as was used previously in your local server program's call to
Compile your client and server programs, and run them in separate terminal windows on your Raspberry Pi. Copy and paste the client and server programs' output as the answer to this exercise.
accept()(but not to
bind()). Your server program should also print a message announcing each time a new connection is established and should then print out the unsigned integer values it reads from the socket each time, to the standard output stream.
Rather than having your server stay alive forever, now modify your
server program so that it terminates when it recieves a special unsigned integer
value (e.g., the http status code
Modify your client so that it can accept zero or one command line arguments, and if it is given the command line argument "quit" it sends that special code to the server after it has sent its other unsigned integers (thus
terminating the server).
Compile your refactored server code and run it in its own terminal window. In another window, run your client program several times along with that server to validate that it can stay alive and keep accepting new connections until it is told to quit. Copy and paste the server output as the answer to this exercise.
Note that for this exercise, your server program will run directly on
You should not
qlogin into a Linux Lab node.
Make copies of your client and server programs, and modify the new copies
to use an internet connection rather than a local connection. Choose a port
number between 30000 and 40000 that both of your programs will use wherever a port
number is needed in the instructions below. Run the command
(on the Raspberry Pi you may need to preface that command with
from a terminal window to obtain the numeric IP address of the
shell.cec.wustl.edu machine, which your client
program should use.
arpa/inet.hin both programs.
connect(), respectively) to specify an internet connection type with
AF_UNIX). Also remove any artifacts of the local domain socket from both programs, including removing the call to
unlink()from the server code.
sockaddr_un) to specify the internet address. This struct is documented at
man 7 ip. In both programs, set the
AF_INET, and the
htons()is a function that translates between the numeric representations used on your computer and in the network, and
port_numis the port number that both your server and client programs are using. In the server program assign the
sin_addr.s_addrfield the value INADDR_ANY, and in the client program use the function
inet_aton()to translate a c-style string containing the target IP address and store it in the
sin_addrfield of the
Compile and run your server on
Compile your client on your Raspberry Pi and run it there twice, once without
telling the server to quit and the second time telling the server to quit.
As the answer to this exercise, copy and paste the output from your client
and server terminal windows. If you cannot connect for whatever reason,
give a descriptive error message using
shell.cec.wustl.edurather than just
shell). After its socket is connected, the client program should also print out that socket's IP address and port. The server program should also print out the IP address and port of the socket on which it is listening, and should also print out the IP address and port of each additional socket that it accepts. As the answer to this exercise please copy and paste all of that output from your client and server terminal windows.
getaddrinfo() functions may be helpful for this exercise.
Please Note: If your Raspberry Pi is not on the school's network, you will need to first establish a remote connection, either with a VPN connection or through an SSH tunnel.
After you have selected all 3 options, click OK to install the packages (you will be prompted to enter the new password you created on your Pi above).
These instructions have been updated to use the new WashU 2FA (two-factor authentication) based VPN. If you have any problems with enrolling in or using WashU 2FA please call the WashU IT ServiceDesk at (314) 933-3333, or email firstname.lastname@example.org.
Once you have installed the VPN, and have enrolled in WashU 2FA and have chosen which authentication method to use, please open up a terminal window on your Raspberry Pi, and
sudo openconnect danforthvpn.wustl.edu
Username: prompt please enter you WUSTL key ID. After that you should get a
Password: prompt, where you should enter your WUSTL key password. You will then get a second prompt that also says
Password: which is where you should enter one of the following keywords (depending on which authentication method(s) you set up when you enrolled in WashU 2FA):
push -- enter this if you have set up DUO mobile notification
(be aware that if you have more than one device enrolled, you may receive the push on only one device)
phone -- enter this if you want to authenticate via a phone call to the number you have registered with the WashU 2FA system (this may only work if you only have registered a single number there).
(note that other methods like entering
sms also may work but involve other details that we have not tested out -
please contact the WashU IT ServiceDesk at (314) 933-3333 or email@example.com, or contact Engineering IT for help using those other methods.)
Note: you will need to go through this process to start the VPN every time you reboot your Raspberry Pi and want to access the linuxlab machines directly from it.
An SSH tunnel allows you to forward traffic on a specific port to a remote server via SSH.
To establish a tunnel, simply run the following command on your Raspberry Pi:
ssh -f -N firstname.lastname@example.org -L port-number:shell.cec.wustl.edu:port-number
You must replace
your-username with your WUSTL Key username, and
port-number with the port you selected to establish the socket connection.
For example, your command might look like:
ssh -f -N email@example.com -L 31522:shell.cec.wustl.edu:31522
After issuing the command, you will be prompted for your WUSTL Key password.
Alternatively, if you are already set up to log in with an SSH key,
you may replace
firstname.lastname@example.org with the server nickname,
as detailed on this page.
If you use the SSH Tunnel approach,
your socket code should be configured to instead connect to the local loopback IP address
127.0.0.1) instead of the IP address you obtained for