Created
December 5, 2025 14:23
-
-
Save arnetheduck/052648f045473c39b91bc565ca40da24 to your computer and use it in GitHub Desktop.
Single socket, multiple threads
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <errno.h> | |
| #include <arpa/inet.h> | |
| #include <netinet/in.h> | |
| #include <sys/socket.h> | |
| #include <pthread.h> | |
| #include <netdb.h> | |
| #define PORT 2001 | |
| #define BACKLOG 128 | |
| #define THREAD_COUNT 3 | |
| typedef struct { | |
| int listen_fd; | |
| int id; | |
| } thread_arg_t; | |
| static void *accept_loop(void *argp) { | |
| thread_arg_t *arg = (thread_arg_t*)argp; | |
| int listen_fd = arg->listen_fd; | |
| int tid = arg->id; | |
| for (;;) { | |
| struct sockaddr_storage ss; | |
| socklen_t slen = sizeof ss; | |
| int client_fd = accept(listen_fd, (struct sockaddr*)&ss, &slen); | |
| if (client_fd < 0) { | |
| if (errno == EINTR) continue; | |
| perror("accept"); | |
| sleep(1); | |
| continue; | |
| } | |
| char host[NI_MAXHOST], serv[NI_MAXSERV]; | |
| if (getnameinfo((struct sockaddr*)&ss, slen, host, sizeof host, serv, sizeof serv, | |
| NI_NUMERICHOST | NI_NUMERICSERV) == 0) { | |
| printf("Thread %d: accepted connection from %s:%s\n", tid, host, serv); | |
| } else { | |
| printf("Thread %d: accepted connection (fd=%d)\n", tid, client_fd); | |
| } | |
| close(client_fd); /* drop connection and accept next */ | |
| break; | |
| } | |
| return NULL; | |
| } | |
| int main(void) { | |
| int listen_fd = socket(AF_INET6, SOCK_STREAM, 0); | |
| if (listen_fd < 0) { | |
| perror("socket"); | |
| return 1; | |
| } | |
| /* Allow both IPv4 and IPv6 (v6->v4 mapping) */ | |
| if (setsockopt(listen_fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof(int)) < 0) { | |
| /* non-fatal on some systems */ | |
| } | |
| struct sockaddr_in6 addr; | |
| memset(&addr, 0, sizeof addr); | |
| addr.sin6_family = AF_INET6; | |
| addr.sin6_addr = in6addr_any; | |
| addr.sin6_port = htons(PORT); | |
| if (bind(listen_fd, (struct sockaddr*)&addr, sizeof addr) < 0) { | |
| perror("bind (need root for ports <1024?)"); | |
| close(listen_fd); | |
| return 1; | |
| } | |
| if (listen(listen_fd, BACKLOG) < 0) { | |
| perror("listen"); | |
| close(listen_fd); | |
| return 1; | |
| } | |
| pthread_t threads[THREAD_COUNT]; | |
| thread_arg_t args[THREAD_COUNT]; | |
| for (int i = 0; i < THREAD_COUNT; ++i) { | |
| args[i].listen_fd = listen_fd; | |
| args[i].id = i; | |
| if (pthread_create(&threads[i], NULL, accept_loop, &args[i]) != 0) { | |
| perror("pthread_create"); | |
| close(listen_fd); | |
| return 1; | |
| } | |
| } | |
| /* Main thread can wait or do other work; join threads to keep process alive */ | |
| for (int i = 0; i < THREAD_COUNT; ++i) { | |
| pthread_join(threads[i], NULL); | |
| } | |
| close(listen_fd); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment