9

I want to attach my service to some TCP port, for testing purposes. Then, I will make calls to this port, make sure the service works, and shut it down. I need to find a way how to generate such a port number, since I can't use a fixed one - tests may run in parallel. Is it possible?

Mike Pennington
  • 41,899
  • 19
  • 136
  • 174
yegor256
  • 102,010
  • 123
  • 446
  • 597

2 Answers2

6

This is how I do it:

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main() {
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    addr.sin_port = 0;
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("socket()");
        return -1;
    }
    if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
        perror("bind()");
        return -1;
    }
    if (getsockname(sock, (struct sockaddr*) &addr, &len) != 0) {
        perror("getsockname()");
        return -1;
    }
    printf("%d\n", addr.sin_port);
    return 0;
}

Then, compile it and run:

cc -o reserve reserve.c && ./reserve

And it outputs the port number, available for binding.

I published a full version of the tool in Github: https://github.com/yegor256/random-tcp-port

yegor256
  • 102,010
  • 123
  • 446
  • 597
  • 2
    Not initialising `struct sockaddr_in addr` to `0` might lead to undefeind behaviour, might crash the app. – alk Nov 09 '12 at 13:45
  • 1
    Also one couldn`t rely on `AF_UNSPEC` being `#define`ed as `0`. – alk Nov 09 '12 at 14:14
  • And you haven't said *why* this works. If indeed it does: I don't see how it can without initialising the socket address structure. – user207421 Nov 09 '12 at 20:46
  • @alk you're right, I updated the answer with an explicit initialization of `addr.sin_port` to zero – yegor256 Nov 11 '12 at 14:54
  • 1
    You need to initialize more than `addr.sin_port`. You need to initalize `.sin_family` to `AF_INET` and `.sin_addr.s_addr` to `INADDR_ANY`. – Robᵩ May 03 '13 at 17:11
2

Just specify port zero when binding; then use getsockname() to find out what port was allocated, so you can tell your clients some other way what port you're listening at. Rarely useful.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 1
    IMO very useful for example during integration tests when you want to start a test server on whatever available port and then pass it to the corresponding test client. Also when you start a set of co-dependent child micro-services from a "parent" program. – morgwai Nov 18 '21 at 19:42