Question

I am using Berkeley sockets (both: Internet domain and Unix domain) and I was wondering if the server can use the same sockets for reading the request and writing a response to the client. Or should the client create an other socket to wait for the replay and the server connect to it after processing the message received.

By the way, I am talking about connection oriented sockets (stream sockets, TCP, ...).

This is the simplified server code (I ommit error checking on system calls here just for simplicity):

int main() {

    int server_socket, connected_socket;
    struct sockaddr_in server_addr;
    char buf[1024];
    char aux[256];
    int bytes_read;

    server_socket = socket(AF_INET, SOCK_STREAM, 0);    

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(1234);
    bind(server_socket, &server_addr, sizeof(server_addr))

    listen(server_socket, 5)

    connected_sodket = accept(server_socket, 0, 0);
    do {
        bzero(buf, sizeof(buf));
        bytes_read = read(connected_socket, buf, sizeof(buf));        
    } while (bytes_read > 0);          

    /* Here I want to use connected_socket to write the reply, can I? */

    close(connected_socket);       

    close(server_socket);

    return (EXIT_SUCCESS);
}

And this is the simplified client code (I ommit error checking on system calls here just for simplicity):

int main() {

    int client_socket;
    struct sockaddr_in server_addr;

    client_socket = socket(AF_INET, SOCK_STREAM, 0);

    hp = gethostbyname("myhost");
    server_addr.sin_family = AF_INET;
    memcpy(&server_addr.sin_addr, hp->h_addr_list[0], hp->h_length);
    server_addr.sin_port = htons(1234);

    connect(client_socket, &server_addr, sizeof(server_addr));

    write(client_socket, MSG, sizeof(MSG));

    /* Here I want to wait for a response from the server using client_socket, can I? */

    close(client_socket);

    return (EXIT_SUCCESS);
}

Can I use connected_socket in the server and client_socket in the client to pass a response message back? Or should I use the client address I get in the server when in "accept" to connect to a socket in the client?

I have tried by using read/wrint in the client/server where the comment is shown but that way both programs keep blocked, it seems to be a dead-lock.

Thanks ins advance! Regards.

Was it helpful?

Solution

You can use the same socket BUT your program is set up to have the server read EVERYTHING the client sends before attempting to reply. So the loop in the server won't complete until the client closes the write side of its socket so the server gets an EOF (0 bytes read), and thus the server will never send back its response.

There are a couple of ways you can deal with this.

  1. You can break the loop in the server after its seen the whole request, rather than reading until EOF. This requires that the data sent by the client be self-delimiting somehow, so the server can know when its read it all.
  2. You can use a second connection for the reply. Probably not the best.
  3. You can use asymmetric shutdown of the socket. Have the client do shutdown(client_socket, SHUT_WR) to half-close the socket. The server will then see the EOF (and the loop will finish), but the other direction on the socket will still be open for the reply.

OTHER TIPS

You should use the same socket!

Your application protocol defines unambiguously when the client and the server should wait for data or send messages to each other; assuming a protocol with only one request from the client and one response from the server, the following should hold:


  • The client establishes a connection with the server;
  • the client sends its request (with send());
  • the client knows, by virtue of the protocol, that the server will reply; therefore it waits for data on the same socket (recv());
  • after validating the response, the client can close the socket.

  • The server accepts a connection from the client;
  • the server knows that the first step is up to the client, hence it waits for data (recv());
  • the server validates the request;
  • the server now knows, from the protocol, that the client is waiting for data; hence it sends its response with send();
  • the server knows, from the protocol, that there are no further steps; hence it can close the socket.

Yes, it's possible. Look check out this page for an example of a simple server (and simple client). Note that the server typically passes the "accept"ed file descriptor into a new process so that it can continue listening for more incoming connections

Not only should you use the same socket (as Federico says), you actually have to in order to get your return packets through firewalls.

Firewalls know about TCP connections, and automatically allow the return data to pass through if a machine inside the firewall initiated the connection. If instead you tried to create a new TCP socket from the outside the firewall would block it unless that traffic was specifically permitted.

Yes, SOCK_STREAM sockets are two-way. You should be able to read and write to/from the same socket on each side of the connection. The man page for socket(2) has more detail on this.

Yes, you can. TCP sockets are bi-directional. Just use the same read() and write() functions. Also make sure to check for error conditions on all calls to connect(), read(), write(), ... as you can't control what happens on the network.

Sorry; I did not say it but I did try it like this

This code in the server where the comment is:

write(connected_socket, "Ok, I got it", sizeof("Ok, I got it"));

and this code in the client where the comment is:

read(client_socket, buf, sizeof(buf));

Both programs keep blocked and when I kill the client, the server shows the messages it received (I have a printf just after the server calls read).

I try it with send and recv (both with 0 flags) instead of read and write and it did not change.

In your current setup the server tries to read until the client closes the socket, while the client doesn't close the socket until the server answered. Therefore you have a kind of "deadlock". The server is not stopping to read in the hope some more data might arrive and the client has no way to tell the server it is done.

You need some way for the server to recognize that the request is complete, while the connection is still open. If you for example terminate your request by a newline, the server can check if it received a full line and then stop reading and send the answer.

Have you tried it? It looks like it should work when you actually put the code in where indicated

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top