/* 
 * 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);
}
codaz/c/c_threaded_tcp_server.txt · Last modified: 2010/01/12 13:29 (external edit)