There’s only one step left before we wrap up and test our little TCP server program–once we send the message, we want to close the connection gracefully. libdill provides a function to do this–tcp_close. Can you help me implement the interface to it? Try exercise 2 in the sidebar.
Exercise 2: Fortran interfaces to suffix_detach and tcp_close
You now know everything you need to know to implement the last two remaining pieces of the server code: suffix_detach and tcp_close. These function calls will be necessary to gracefully close the TCP connection from the client. Here’s the prototype for the suffix_detach function:
int suffix_detach(
int s,
int64_t deadline);
And here’s the prototype of the tcp_close function:
int tcp_close(
int s,
int64_t deadline);
If implemented correctly in the mod_dill module, you’ll be able to import these interfaces and call them from the main server loop:
connection = suffix_detach(connection, -1_c_int64_t)
rc = tcp_close(connection, -1_c_int64_t)
The solution to this exercise is given in the “Answer key” section near the end of the chapter.
Our server loop will now look like the following listing.
Listing 11.7 The main loop that accepts a connection and sends a message
do
connection = tcp_accept(socket, addr_remote, -1_c_int64_t)
call ipaddr_str(addr, address_string)
print *, 'New connection from ' // trim(address_string)
connection = suffix_attach(connection, TCP_SUFFIX, 2_c_size_t)
rc = msend(connection, 'Hello' // c_null_char, 5_c_size_t, -1_c_int64_t)
connection = suffix_detach(connection, -1_c_int64_t)
rc = tcp_close(connection, -1_c_int64_t)
end do
That’s it! Our server will now accept an incoming connection, send a greeting message to the client, and close the connection.
Let’s see how it works from the client side. First, compile and run the server from one terminal session:
gfortran mod_dill.f90 server.f90 libdill.a -pthread -o server
./server
Listening on socket:
IP address: 127.0.0.1
Port: 5555
In another terminal session, you can use a variety of command-line tools (curl, netcat, telnet) to connect to our Fortran server:
curl 127.0.0.1:5555 ❶
Hello
nc 127.0.0.1 5555 ❷
Hello
telnet 127.0.0.1 5555 ❸
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Hello
Connection closed by foreign host.
❶ Connects to the server using curl
❷ Connects to the server using nc (netcat)
❸ Connects to the server using telnet
Voila! This confirms that our minimal Fortran web server is reachable using language-agnostic networking tools and returns the expected result. All of these tools are available out of the box on most modern Linux distributions. If not, you can easily install them using the system package manager. On macOS, they may or may not be available out of the box but can be downloaded and installed. On Windows, I recommend that you use the recent Windows Terminal or the Windows Subsystem for Linux.
Our minimal TCP server emits a response as a raw sequence of bytes, without any descriptive headers that are characteristic of HTTP responses. Some newer versions of curl may expect an HTTP response by default and may return an error message:
curl: (1) Received HTTP/0.9 when not allowed
To work around this, invoke curl like this:
curl --http0.9 127.0.0.1:5555
At this point, you should have the following files in your working directory:
- libdill.a –A compiled archive file for the libdill library
- mod_dill.f 90 –A Fortran source file containing the
mod_dillmodule, which defines and makes available the following entities:ipaddr,ipaddr_local,ipaddr_port,ipaddr_str,IPADDR_MAXSTRLEN,IPADDR_IPV4,msend,suffix _attach,suffix _detach,tcp_accept,tcp_close, andtcp_listen - server.f 90 –A Fortran source file containing the server program that imports the procedures and constants and uses them to listen for incoming connections to an open socket
Now that we’ve implemented the server, let’s write the client program.