2

This is a very basic question on UDP sockets. I myself have programmed some server/client application using them, but I'm stuck now and not able to see where the problem is.

I'm trying to do a server and a client which can both send and receive datagrams. So the server waits for a petition from the client on a determined socket, when it receives something through it, it sends its answer to the client. It works as far as the server getting the petition and sending answer back, but the client never gets it.

I show here some stripped code, just the basic part of the connection:

SERVER:

if ((socket_id = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
    return;
}

bzero(&server_socket, sizeof(server_socket));
server_socket.sin_family = AF_INET;
server_socket.sin_addr.s_addr = INADDR_ANY;
server_socket.sin_port = htons(8724);

if (bind(socket_id, (struct sockaddr *) &server_socket, sizeof(server_socket)) == -1) {
    return;
}

bzero(dgram_buffer, 1024);
client_socket_sz = sizeof(client_socket);
if((dgram_length = recvfrom(socket_id, dgram_buffer, 1024, 0, (struct sockaddr *) &client_socket, (socklen_t *) &client_socket_sz)) == -1) {

    return;
}
if (sendto(socket_id, msg_buffer, offset, 0, (struct sockaddr *) &client_socket, (socklen_t) client_socket_sz) < 0) {

    return;
}
printf("%s\n", msg_buffer);

CLIENT:

if ((socket_id = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
        return;
}

if ((hostp = gethostbyname(hostname)) == 0) {
    return;
}
bzero((char *) &client_socket, sizeof(client_socket));
client_socket.sin_family = AF_INET;
client_socket.sin_port = htons(8724);
bcopy(hostp->h_addr, (char *) &client_socket.sin_addr, hostp->h_length);

bzero(msg_buffer,sizeof(msg_buffer));
memcpy(msg_buffer,"mensaje\0",sizeof("message"));

socklen_t client_socket_len = sizeof(struct sockaddr_in);
if (sendto(socket_id, msg_buffer, sizeof(msg_buffer), 0, (struct sockaddr *) &client_socket, client_socket_len) < 0) {
    return;
}
bzero(msg_buffer,sizeof(msg_buffer));
if(recvfrom(socket_id, msg_buffer, sizeof(msg_buffer), 0, (struct sockaddr *) &client_socket, &client_socket_len) == -1) {
    return;
}
printf("%s\n", msg_buffer);

(I know that the buffers and their contents are not very well treated; I'm doing it correctly on my real application, I just typed that to get a quick test)

Could anyone give it a look and tell me if some setting is wrong? I've seen hundreds of examples on the net, reviewed old code of mine... to no avail. Maybe I've been on this for too many hours and I'm just skipping the obvious.

Thanks in advance.

freieschaf
  • 530
  • 1
  • 5
  • 13
  • Can you give us something that compiles? – William Morris May 06 '12 at 13:29
  • BTW, does it work with hostname == "localhost" - ie. client and server on the same machine? I just compiled it up and it worked on OS X – William Morris May 06 '12 at 13:33
  • I tried switching the machines I execute the server (remote) and client (local) and then it was the server (now local) that wasn't getting any message. So I executed both on two different remote machines (on the same network, though) and at least this simple code I posted here was executing fine. Does that mean that this is a problem with my local machine? – freieschaf May 06 '12 at 13:35
  • Probably a firewall problem. How do you connect to the internet? – William Morris May 06 '12 at 13:37
  • @WilliamMorris Here you can find the server: (http://pastebin.com/7D9ty5Hv) and the client: (http://pastebin.com/UxnVTzun) – freieschaf May 06 '12 at 13:41
  • @WilliamMorris I'm not using any firewall that I know of... But I'm not really sure of how that works. I'm just connected to my home wireless. – freieschaf May 06 '12 at 13:44
  • `sizeof("message")` == `sizeof(char *)` – wildplasser May 06 '12 at 13:53
  • Interesting. I have copies of your server running on bonn.contextshift.co.uk and entropy.contextshift.co.uk. With `bonn`, the client gets no reply. With `entropy` it does! I added a loop so that the servers continually receive and reply - try connecting to them. I had a problem like this a while back that I never resolved: http://stackoverflow.com/questions/9594332/udp-hole-punching-host-specific-failure – William Morris May 06 '12 at 13:58
  • @WilliamMorris Tried on both of your servers but didn't get any response. This is wicked. – freieschaf May 06 '12 at 14:17
  • I'm in the C chat room now if you wan to talk – William Morris May 06 '12 at 14:49

2 Answers2

0

You need to bind both sockets.

You already bind the server, to a well-known port.
You should also bind the client, to port 0. This means the OS chooses an arbitrary port for this session. While the socket is bound, you'll get packets to that port.

ugoren
  • 16,023
  • 3
  • 35
  • 65
  • Thanks for the quick reply:) I've tried that but the client doesn't get the response anyway. – freieschaf May 06 '12 at 13:06
  • Try to snoop the traffic (tcpdump/wireshark) and see what's sent. Use `netstat` to see which process listens on which port. – ugoren May 06 '12 at 13:10
  • I was using strace on both server and client and it shows just that: server has received petition and sent response, client sent petition and keeps waiting for a response. As it hangs there, I don't find the port to which the server is replying executing netstat on the client side. Should that mean anything? – freieschaf May 06 '12 at 13:19
  • It seems like you didn't bind the client port. After you bind it, you can use `getsockname` to see which port number you got. Then you should also see it in `netstat`. – ugoren May 06 '12 at 20:09
0

Just a guess. Try reading from socket in a 'while' loop. Something like that:

int received = 0;
int tmp;
int expected = ...
while(received != expected){
    tmp = recvfrom(socket_id, msg_buffer, sizeof(msg_buffer), 0, (struct sockaddr *) &client_socket, &client_socket_len)
    if(tmp == -1){ ... }
    received += tmp;
}
Pawel Batko
  • 761
  • 7
  • 19
  • The thing is that I don't really know the size of the message I am expecting. In fact, the workflow in my application is based on that variable size, so I cannot loop recvfrom() that way. – freieschaf May 06 '12 at 13:22
  • Particular in the case of varying message sizes you'll have to use the returned value from read() or recv(). – wildplasser May 06 '12 at 13:55
  • @freieschaf: if you don't know the size of your incoming data, you're either going to have to live with dropping part of your packet, or you're going to have to allocate a buffer large enough to hold the largest UDP packet possible (64k, IIRC). Welcome to the world of input validation. – tbert May 06 '12 at 14:30
  • @tbert: My client and server both have buffers of a fixed max size. When they receive a datagram, they use the size of received data: if it is the max size, they keep receiving; if it's less than that size, end of transmission. I don't think there is any problem there, as the client isn't receiving any data yet. – freieschaf May 06 '12 at 14:44