0
votes

I have a Linux C application that must use UDP. The server broadcasts a "discovery packet" and then listens for any connected clients to answer with a similar echo. By using ports, the clients and server can then communicate using their different ports.

Here is how the server broadcasts its discovery packet:

int main() {
  puts("starting");
  int sock;
  int yes = 1;
  struct sockaddr_in broadcast_addr;
  int addr_len;
  int count;
  int ret;
  fd_set readfd;
  char buffer[1024];
  char outbound_buffer[63];
  int i;

  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) {
    perror("sock error");
    return -1;
  }
  ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
  if (ret == -1) {
    perror("setsockopt error");
    return 0;
  }
  memset(outbound_buffer,0,sizeof(outbound_buffer));

  addr_len = sizeof(struct sockaddr_in);

  memset((void*)&broadcast_addr, 0, addr_len);
  broadcast_addr.sin_family = AF_INET;
  broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
  broadcast_addr.sin_port = htons(PORT);

  outbound_buffer[0] = 0xEF;
  outbound_buffer[1] = 0xFE;
  outbound_buffer[2] = 0x02;

    ret = sendto(sock, outbound_buffer, 63, 0, (struct sockaddr*) &broadcast_addr, addr_len);

This works fine; the client receives the discovery and gets the server's IP and port:

int main() {

  stoplink = 0;
  stopData = 0;
  int addr_len;
  int count;
  int ret;
  fd_set readfd;
  char buffer[1024];
  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) {
    perror("sock error\n");
    return -1;
  }
  addr_len = sizeof(struct sockaddr_in);
  memset((void*)&server_addr, 0, addr_len);
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htons(INADDR_ANY);
  server_addr.sin_port = htons(PORT);

  ret = bind(sock, (struct sockaddr*)&server_addr, addr_len);
  if (ret < 0) {
    perror("bind error\n");
    return -1;
  }
  while (1) {

  puts("Initialized; await discovery");

    FD_ZERO(&readfd);
    FD_SET(sock, &readfd);

    ret = select(sock+1, &readfd, NULL, NULL, 0);
    if (ret > 0) {
      if (FD_ISSET(sock, &readfd)) {
        count = recvfrom(sock, buffer, 1024, 0, (struct sockaddr*)&client_addr, &addr_len);
        if((buffer[0] & 0xFF) == 0xEF && (buffer[1] & 0xFF) == 0xFE) {
      fprintf(stderr,"discovery packet detected\n"); 
          cmdport = ntohs(client_addr.sin_port);
          printf("\nClient connection information:\n\t IP: %s, Port: %d\n", 
            inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

       count = sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&client_addr,
         sizeof(client_addr));
        }
      }
    }

  puts("Now starting command processing loop");

This also works fine... but it sends the reply to the port on the server from which the broadcast came - this was randomly selected automatically by the server; so how do I know what port to listen to on the server side to receive the client's reply?

3
That's why you should bind the socket in the "server" side, so it doesn't get a random port and you can select it yourself.Some programmer dude
The answer to the question in your title is getsockname(), but you don't need it.user207421

3 Answers

1
votes

The server doesn't need to do anything additional. Once it sends a packet, the port on the server side is set.

For example, if the client sees that the server message came from port 34567, then the server socket is using port 34567. Then any messages sent to the server at port 34567 can be read by the same server socket.

So the server can just call recvfrom and it will get the response from the client.

0
votes

You've swapped the normal meanings of the words "client" and "server" -- normally the server will bind to a specific port and listen for (broadcast) packets, while the client will broadcast a discovery packet to find the server. When the server receives a broadcast, it will reply to the client, which will just do a recv on it's (single) socket to get the reply, which will have the server's IP address. If there might be multiple servers, then they'll all reply to the client, so the client will see multiple replies and need to choose from them. But, most importantly, the client never needs to actually know which port it is using -- it just lets the system choose an otherwise unused port for it.

0
votes

Thanks for all the input. getsockname() is what I needed.