/* * threaded TCP server template * Copyright (c) 2004 iMil <imil @gcu.info>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by iMil. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY iMil AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL iMil OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $Id$ */ /* BSD Makefile * * #--- begin * PROG= whatyouwant * LDADD+= -pthread * NOMAN= true * * .include <bsd .prog.mk> * #--- end */ /* google related keywords so you can find this code easily * example exemple tcp server serveur thread threads pthread pthreads * hope it helps you somewhat, I don't pretend it's a perfect code (far away * from it) but maybe it could save you some hours. * Feel free to contribute ! * iMil </imil><imil @gcu.info> */ #include <limits.h> #include <stdio.h> #include <stdarg.h>; #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #include <pthread.h> #define SVR_PORT 6666 #define MAXLEN LINE_MAX #define D_WARN 5 int verbose = 1; /* debug printf, show info if global verbose >= verbosity */ void d_printf(uint8_t verbosity, char *fmt, ...) { char buffer[MAXLEN]; if (verbose >= verbosity ) { va_list args; va_start(args, fmt); vsnprintf(buffer, MAXLEN, fmt, args); fprintf(stderr, "%s", buffer); va_end(args); } } void * service(void *arg) { int fd = (int)arg; pthread_detach(pthread_self()); /* do whatever you want here */ close(fd); pthread_exit(NULL); } void sighandle(int signo) { if ((signo==SIGTERM) || (signo==SIGINT)) { exit(0); } if (signo == SIGHUP) { } if (signo == SIGALRM) { } } int main(int argc, char *argv[]) { int port = SVR_PORT; int clt_fd,srv_fd; struct sockaddr_in local_addr; struct sockaddr_in clt_addr; socklen_t sin_size; int yes = 1, err; pthread_t tid; struct timeval timeout = {5, 0}; struct linger lng = {1, 5}; time_t stamp; /* ignore SIGPIPE and catch SIGTERM|INT */ if (signal(SIGPIPE, sighandle) == SIG_ERR) fprintf(stderr, "can't catch SIGPIPE signal\n"); if (signal(SIGTERM, sighandle) == SIG_ERR) fprintf(stderr, "can't catch SIGTERM signal\n"); if (signal(SIGINT, sighandle) == SIG_ERR) fprintf(stderr, "can't catch SIGINT signal\n"); if (signal(SIGALRM, sighandle) == SIG_ERR) fprintf(stderr, "can't catch SIGALRM signal\n"); if (signal(SIGHUP, sighandle) == SIG_ERR) fprintf(stderr, "can't catch SIGHUP signal\n"); if ((srv_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } local_addr.sin_family = AF_INET; local_addr.sin_port = htons(port); local_addr.sin_addr.s_addr = INADDR_ANY; memset(&(local_addr.sin_zero), 0, 8); if (setsockopt(srv_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){ perror("setsockopt"); exit(1); } setsockopt(srv_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)); setsockopt(srv_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)); setsockopt(srv_fd, SOL_SOCKET, SO_LINGER, &lng, sizeof(struct linger)); if (bind(srv_fd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr)) == -1) { perror("bind"); exit(1); } if (listen(srv_fd, 5) < 0) { perror("listen"); exit(1); } while(1) { sin_size = sizeof(struct sockaddr_in); if ((clt_fd = accept(srv_fd, (struct sockaddr *)&clt_addr, &sin_size)) < 0) { continue; } err = pthread_create(&tid, NULL, service, (void *)clt_fd); if (err != 0) d_printf(D_WARN, "error creating thread, err: %d\n", err); } /* never reached */ return (0); }