In the previous section, you learned how to send a TCP message from the server to a remote client by calling the msend function in libdill. We tested that it worked by communicating to the server with command-line networking tools such as curl, nc, and telnet. What if you wanted to exchange data over the network between two Fortran programs? We need to have a mechanism for receiving a message in the Fortran client program. Now we’ll implement mrecv, the sibling of msend:
ssize_t mrecv(
int s,
void* buf,
size_t len,
int64_t deadline);
If you look back at the msend prototype in listing 11.6, you’ll see that mrecv has exactly the same definition, except for two important differences:
- The return value of the function is now of type
ssize_tinstead ofint. Inmsend, the function result was just a status code, indicating success or the kind of error that the function encountered. Inmrecv, however, the return value is the length of the message. Its type,ssize_t, is the signed variant of thesize_ttype. It’s an integer that can have extremely large values, but, unlikesize_t, can also represent negative values. This is useful because with assize_t-typed result, this function can return the length of the message if successful, and -1 in case of an error. - The buffer
bufis not aconstanymore, which means that its value can (and in this case, will) be written insidemrecv. This has an important implication for our Fortran interface–whereas inmsendwe declared thebufargument asintent(in), here we’ll declare it asintent(out).
With these two considerations, we can proceed to write the Fortran interface to mrecv as
integer(c_size_t) & ❶
function mrecv(s, buf, len, deadline) & ❶
bind(c, name='dill_mrecv') ❷
import :: c_char, c_int, c_int64_t, c_size_t ❸
integer(c_int), value, intent(in) :: s ❹
character(c_char), intent(out) :: buf(*) ❺
integer(c_size_t), value, intent(in) :: len ❻
integer(c_int64_t), value, intent(in) :: deadline ❼
end function mrecv
❶ The return value is of type c_size_t.
❸ Imports all the equivalent C-types into the local scope
❹ The first input argument is a socket and is passed by value.
❺ The character buffer is the output argument and is passed by reference.
❻ The buffer length is an integer of kind c_size_t and is passed by value.
❼ The last argument is an integer of kind c_int64_t and is also passed by value.
Interfacing unsigned and signed integers
Whereas C has signed and unsigned (positive only) integers, Fortran has only signed integers. Unsigned (size_t) and signed (ssize_t) C integers are thus matched with the same type kind parameter in Fortran, just c_size_t. Perhaps counterintuitive to its name, c_size_t is signed.