Architecture/Lecture/tcpsrv0.3
From Apache OpenOffice Wiki
< Architecture | Lecture
The same functionality without using select or poll but using pthread
first the header file as addition to the original header file tcpsrv.h
/* include th_tcpsrv.h */ /* Tabs are set for 4 spaces, not 8 */ #ifndef __th_tcpsrv_h #define __th_tcpsrv_h #include <pthread.h> #define MAXFD 20 volatile fd_set sock_fdset; pthread_mutex_t mutex_state = PTHREAD_MUTEX_INITIALIZER; #endif
and th_tcpsrv.c - both headers tcpsrv.h and th_tcpsrv.h need to be included
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ /* * th_tcpsrv.c Vers. 0.3 * Copyright (C) Stefan Zimmermann 2008 <sz@sun.com> * * th_tcpsrv.c is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * th_tcpsrv.c is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. * * The server waits on TCP Port PORT for connection requests from * telnet clients. The client sends ASCII messages to the server. * This messages will be sent from the server then to all other connected clients. * * start server with: * ./th_tcpsrv & * * start client with: * telnet _serverIPadresse_ PORT */ #include "tcpsrv.h" #include "th_tcpsrv.h" int listen_socket(int port) /* open server (listen) port - called only once * in port: port number where TCP server is supposed to listen * return: server socket file descriptor to connect from client(s) */ { int srv_sockfd; int ret; struct sockaddr_in sockadr; int yes = 1; /* create the socket */ srv_sockfd = socket(PF_INET, SOCK_STREAM, 0); exit_if(srv_sockfd < 0); /* prevent "error address already in use" message */ ret = setsockopt(srv_sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); exit_if(ret < 0); memset((char *) &sockadr, 0, sizeof(sockadr)); sockadr.sin_family = AF_INET; sockadr.sin_addr.s_addr = htonl(INADDR_ANY); sockadr.sin_port = htons(port); /* bind created socket to port */ ret = bind(srv_sockfd, (struct sockaddr *) &sockadr, sizeof(sockadr)); exit_if(ret != 0); ret = listen(srv_sockfd, 5); exit_if(ret < 0); return srv_sockfd; } int accept_socket(int srv_sockfd) /* open communication (connection) - execute for every new client * in srv_sockfd: socket file descriptor to connect from client * return: if okay socket file descriptor to read from client, ERROR otherwise */ { int client_fd; struct sockaddr_in sockadr; socklen_t socklen; socklen = sizeof(sockadr); client_fd = accept(srv_sockfd, (struct sockaddr *) &sockadr, &socklen); return_if(client_fd < 0, ERROR); printf("Connected %s:%d\n", (char*)inet_ntoa(sockadr.sin_addr), ntohs(sockadr.sin_port)); return client_fd; } int socket_write(int client_fd, char buf[], int buflen) /* write to the client socket interface * in fd: socket file descriptor to write to client * in buf: message to write * in buflen: length of message * return: OKAY if write was completed, ERROR otherwise */ { int ret; ret = send(client_fd, buf, buflen, 0); return_if(ret != buflen, ERROR); return OKAY; } void *socket_read(void *fdptr) /* thread for one CONNECT port * read from client socket interface * in fdptr: socket file descriptor to read from client * return: */ { int client_rfd; char buf[MAXLEN]; int buflen; int client_wfd; client_rfd = (int)fdptr; for(;;) { /* read message */ buflen = recv(client_rfd, buf, sizeof(buf), 0); if (buflen <= 0 || strncmp("quit\r", buf,5) == 0) { /* end of TCP connection */ pthread_mutex_lock(&mutex_state); FD_CLR(client_rfd, &sock_fdset); /* remove client rfd */ pthread_mutex_unlock(&mutex_state); close(client_rfd); pthread_exit(NULL); } /* write message to all other clients */ pthread_mutex_lock(&mutex_state); for (client_wfd = 3; client_wfd < MAXFD; ++client_wfd) { if (FD_ISSET(client_wfd, &sock_fdset) && (client_rfd != client_wfd)) { socket_write(client_wfd, buf, buflen); } } pthread_mutex_unlock(&mutex_state); } return NULL; } void srv_loop(int srv_sockfd) /* server loop * in listen_fd: socket file descriptor to connect to the client */ { pthread_t threads[MAXFD]; FD_ZERO(&sock_fdset); for (;;) { /* loop */ int client_rfd; void *arg; /* check TCP server PORT for client connect */ client_rfd = accept_socket(srv_sockfd); if (client_rfd >= 0) { if (client_rfd >= MAXFD) { close(client_rfd); continue; } pthread_mutex_lock(&mutex_state); FD_SET(client_rfd, &sock_fdset); /* add new client */ pthread_mutex_unlock(&mutex_state); arg = (void *) client_rfd; pthread_create(&threads[client_rfd], NULL, socket_read, arg); } } } int main(int argc, char *argv[]) { /* enable error logging */ openlog(NULL, LOG_PERROR, LOG_WARNING); /* open tcpsrv */ srv_loop(listen_socket(PORT)); return OKAY; }