地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Linux】so_reuseportに関して

背景

so_reuseportってなんやねんと思って調べた

SO_REUSEPORTとは

ローカルアドレスの再使用を有効にするソケットオプションのSO_REUSEADDRは使ったことがあったがportは使ったことがなかった。manを参照すると「重複したアドレスとポートのバインドを有効にします」と書いてある。そのままだった。

これの何が嬉しいのかというと例えば複数プロセスのソケットプログラミングを行う際にマルチプロセスモデルで書く場合にこのオプションを指定しない場合は親プロセスでListenして子プロセスでそのsocketをaccept(2)する必要がある。このオプションを使うと各子プロセスでbindすることが可能となる。

Nginxでの使い方

Socket Sharding in NGINX OSS Release 1.9.1

Nginxの場合のわかりやすい図。使わない場合は各workerがリクエストごとに接続を取得しようとする。

f:id:ryuichi1208:20210626181905p:plain

サンプルソース

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <netinet/in.h>

void child(int idx)
{
        int S, C;
        const int on = 1;
        struct addrinfo *res;
        struct addrinfo hints;
        struct sockaddr_in sin4;
        socklen_t slen;

        memset(&hints, sizeof(hints), 0);
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
        getaddrinfo("127.0.0.1", "10000", &hints, &res);
        S = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        setsockopt(S, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
        bind(S, res->ai_addr, res->ai_addrlen);
        freeaddrinfo(res);
        listen(S, 100);

        slen = sizeof(sin4);
        while ((C = accept(S, (struct sockaddr *)&sin4, &slen)) >= 0) {
                close(C);
                printf("accepted by child #%d\n", idx);
        }
}

int main(void)
{
        int status;
        int i;

        for (i = 0; i < 4; i++) {
                pid_t pid = fork();
                if (pid == 0) {
                        child(i);
                        return 0;
                } else if (pid < 0) {
                        perror("fork");
                        return 1;
                }
        }

        wait(&status);

        return 0;
}

参考