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;
}