Sockets are a fundamental abstraction for many types of computer communication- both inside a single machine and over networks. They are the basic primitives used to connect machines together, and they are used to implement all kinds of networked communication. Despite this, they are surprisingly simple to use, as they encapsulate and hide virtually all of the technical details need to accomplish such communication, and are accessed (like many other things in Linux) just like you were reading or writing a local file or pipe.
In this studio, you will:
Please complete the required exercises below, as well as any optional enrichment exercises that you wish to complete.
As you work through these exercises, please record your answers, and when finished email your results to dferry@email.wustl.edu with the phrase Sockets Studio in the subject line.
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 bind
under the section
labeled EXAMPLE.
Your server should perform the following actions:
socket()
. To
create a local connection use the domain AF_LOCAL
(or equivalently 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. Directions on how to specify a local address in this way can be
found at man 7 unix
.
listen()
system
call. Sockets only allow one process to connect at a time, so the second parameter
determines how many connection requests can wait in line before they are rejected.
accept()
system call to accept a connection
over the socket interface. If no connection is immediately available then this
system call will, by default, cause your program block until another program
attempts to connect.
unlink()
in order to destroy
the socket and connection before the program returns.
When your program successfully returns from accept()
the
connection has been established. You may read and write data over the channel
with the lower level read()
and write()
system
calls, or you can instantiate a stream interface with the fdopen
function. When doing so, be sure to use the socket descriptor returned by
the call to accept()
, not the one created by the initial call
to socket()
.
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 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 string.h
and
errno.h
.
socket()
system call.
connect()
system call. This
requires using the same socket address struct as the call to bind()
.
At this point, barring any errors, your communcations channel is ready to be used. Send some messages to the server program and print them to standard output in order to validate the functionality. Copy and paste the server output as the answer to this exercise. Note that, like with pipes, a call to read an empty socket will block until data is available.
accept()
, but not to
listen()
or bind()
.
Print a message each time a new connection is established and run your client program
several times with the same server to validate this behavior. Copy and paste
the server output as the answer to this exercise.
strncmp
to test for string equality. The similar function
strcmp
is difficult to use with large buffers.
Copy and paste terminal output demonstrating this functionality
Use your client program as a template, but we will modify it to use an
internet connection rather than a local connection. You will connect to
port 17000
at IP address 24.107.185.147
.
netinet/ip.h
and arpa/inet.h
.
socket()
to specify an internet connection
type with AF_INET
.
sockaddr_in
to specify the internet
address. This struct is documented at man 7 ip
. Set the
sin_family
field to AF_INET
, the sin_port
field to htons(port_num)
, where htons()
is a function
that translates between numeric representations on your computer and the network.
Third, use the function inet_aton()
to translate a c-style string
containing the target IP address and store it at sin_addr
using the
second argument.
connect()
After opening the
connection, read the message from the socket and print it to standard out. This
server will refuse any data you send to it.
As the answer to this question, copy and paste the output from your terminal.
If you cannot connect for whatever reason, give a descriptive error message using
strerror()
and errno
.