Architecture/Lecture/tcpsrv0.3

From Apache OpenOffice Wiki
< Architecture‎ | Lecture
Revision as of 09:16, 25 November 2009 by B michaelsen (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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