Если вы не хотите изменять количество доступных временных портов (как предложено Дэвидом), или вам нужно больше соединений, чем теоретический максимум, есть два других способа уменьшить количество используемых портов. Однако они в различной степени являются нарушением стандарта TCP, поэтому их следует использовать с осторожностью.
Первый - включить SO_LINGER
с тайм-аутом в ноль секунд, заставляя стек TCP
отправлять RST-пакет и сбрасывать состояние соединения. Однако есть одна тонкость: вы должны вызвать shutdown
в дескрипторе файла сокета перед close
, чтобы у вас была возможность отправить пакет FIN
перед пакетом RST
. Таким образом, код будет выглядеть примерно так:
shutdown(fd, SHUT_RDWR);
struct linger linger;
linger.l_onoff = 1;
linger.l_linger = 0;
// todo: test for error
setsockopt(fd, SOL_SOCKET, SO_LINGER,
(char *) &linger, sizeof(linger));
close(fd);
Сервер должен видеть преждевременный сброс соединения, только если пакет FIN
переупорядочен с пакетом RST
.
См. Опция TCP SO_LINGER (ноль) - когда это требуется для получения более подробной информации. (Экспериментально, кажется, не имеет значения, где вы установили setsockopt
.)
Второй - использовать SO_REUSEADDR
и явный bind
(даже если вы клиент), что позволит Linux повторно использовать временные порты при запуске, прежде чем они будут ждать. Обратите внимание, что необходимо использовать bind
с INADDR_ANY
и портом 0
, в противном случае SO_REUSEADDR
не соблюдается. Ваш код будет выглядеть примерно так:
int opts = 1;
// todo: test for error
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *) &opts, sizeof(int));
struct sockaddr_in listen_addr;
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = 0;
listen_addr.sin_addr.s_addr = INADDR_ANY;
// todo: test for error
bind(fd, (struct sockaddr *) &listen_addr, sizeof(listen_addr));
// todo: test for addr
// saddr is the struct sockaddr_in you're connecting to
connect(fd, (struct sockaddr *) &saddr, sizeof(saddr));
Эта опция менее хороша, потому что вы все равно будете насыщать внутренние структуры данных ядра для соединений TCP согласно netstat -an | grep -e tcp -e udp | wc -l
. Однако вы не начнете повторно использовать порты, пока это не произойдет.