echo client using threads
- From: arnuld <sunrise@xxxxxxxxxxxxxxx>
- Date: Tue, 15 Jul 2008 09:46:30 +0500
WANTED: This program is a TCP echo server-client. server is written using
poll() while client is written using threads.
1.) server recv()s some characters from a client and then echoes the
characters to all clients except the one who sent it.
2.) client has 2 threads, one thread send()s something to the server
once, 2nd thread waits infinitely for recv(), as I want the thread to
remain connected to recv() the input.
PROBLEM: one client disconnects as soon as another connects. after that
no client remains connected. After 2 or 3 attempts server
disconnects too.
I am at the bginning stage of learning TCP/IP things, as you already know
and most of the things I have written do not make much sense to me. e.g. I
do know what socket(), bind(), listen(), connect(), send() and recv() work
but I do not have much idea about how poll() works and when server poll()
starts etc. I just did it as told in UNP volume 1.
--------------------------- poll-server.c ------------------------------------
/* A server handeling multiple clients using poll()
VERSION: 1.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#define SERVER_IP "127.0.0.1"
enum { ARRSIZE = 101, BACKLOG = 100, OPEN_MAX = 12 };
int main( int argc, char** argv )
{
int sockfd, accept_fd, tempfd, myport;
struct sockaddr_in servaddr, cliaddr;
socklen_t clilen;
char arrc[ARRSIZE];
/* preparations for poll() */
struct pollfd clients[OPEN_MAX];
int i, j, recv_bytes, nready;
int curr_index, max_index;
/* clear the array and the address structures */
memset( arrc, '\0', ARRSIZE );
memset( &servaddr, '\0', sizeof(servaddr) );
memset( &cliaddr, '\0', sizeof(cliaddr) );
if( argc != 2 )
{
fprintf(stderr, "USAGE: ./file PORT\n");
exit( EXIT_FAILURE );
}
else
{
myport = atoi( argv[1] );
}
if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("SOCKET() error\n");
exit( EXIT_FAILURE );
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(myport);
if( inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr) <= 0 )
{
perror("inet_pton: error\n");
exit(EXIT_FAILURE);
}
if( bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr)) < 0 )
{
perror("BIND() error\n");
exit( EXIT_FAILURE );
}
if( listen(sockfd, BACKLOG) < 0 )
{
perror("LISTEN() error\n");
exit( EXIT_FAILURE );
}
/* poll() initialisation */
clients[0].fd = sockfd;
clients[0].events = POLLIN;
max_index = 0;
curr_index = 0;
for(i = 1; i < OPEN_MAX; ++i )
{
clients[i].fd = -1;
}
/* here we start to accept connections */
for( ; ; )
{
if( (nready = poll(clients, max_index + 1, -1)) <= 0 )
{
perror("can not POLL()");
exit( EXIT_FAILURE );
}
if( clients[0].revents & POLLIN )
{
clilen = sizeof( cliaddr );
accept_fd = accept(sockfd, (struct sockaddr*)&cliaddr, &clilen);
printf("ACCEPT()ed \n");
/* check if the poll() is full of connections
this solution is buggy */
if( curr_index > OPEN_MAX )
{
fprintf(stdout, "I am not supposed to accept more than %d connections\n", OPEN_MAX);
continue;
}
/* add the new FD to the poll() */
for( i=1; i < OPEN_MAX; ++i )
{
if( clients[i].fd < 0 )
{
clients[i].fd = accept_fd;
printf("added FD#%d in clients[%d]\n", clients[i].fd, i);
break;
}
}
curr_index = i;
printf("curr_index = %d\n", curr_index);
/* After the check, now we can add to events */
clients[curr_index].events = POLLIN;
if( (curr_index > max_index) && (curr_index < OPEN_MAX) )
{
max_index = curr_index;
}
if( --nready <= 0 )
{
continue;
}
} /* if condition for checking connection is done with */
/* now we check & read the data */
for( i = 1; i <= max_index; ++i )
{
if( (tempfd = clients[i].fd) < 0 )
{
continue;
}
if( clients[i].revents & (POLLIN | POLLERR) )
{
if( (recv_bytes = recv(tempfd, arrc, ARRSIZE, 0)) <= 0 )
{
perror("remote-client CLOSED the connection.");
close( tempfd );
tempfd = -1;
}
else
{
printf("RECV()ed Data...\n");
/* here we we will send this data to every accepted file-decriptor
stored on poll array named clients. We do so using a for loop
till we hit the max_index.
*/
for( j=1; j <= max_index; j++ )
{
if( clients[j].fd > 0 )
{
/* this prevents the server to write back to the client who sent the message.
* we only need to write to all other clients except the one who sent the
* data to server. */
if( i != j )
{
if( send( clients[j].fd, arrc, ARRSIZE, 0 ) < 0 )
{
fprintf(stdout, "SEND() error to # %d\n", clients[j].fd);
}
else
{
printf("written to %d, FD# %d\t i = %d, iFD#= %d\n", j, clients[j].fd, i, clients[i].fd);
}
}
}
}
}
printf("::\n");
if( --nready <= 0 )
{
break;
}
}
}
}
return 0;
}
--------------------------- thread-client.c ------------------------------------
/* a client using threads to send() and recv() messages to and from server */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <pthread.h>
#define SERVER_IP "127.0.0.1"
enum { ARRSIZE = 101, FD_ARRSIZE = 1 };
static void* send_function( void * );
static void* recv_function( void * );
int main( int argc, char* argv[] )
{
int sockfd, myport;
struct sockaddr_in cliaddr;
memset( &cliaddr, '\0', sizeof(struct sockaddr_in) );
/* thread preparations */
pthread_t tid_send, tid_recv;
if( 2 == argc )
{
myport = atoi( argv[1] );
}
else
{
perror("USAGE: ./file PORT");
exit( EXIT_FAILURE );
}
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(myport);
if( inet_pton( AF_INET, SERVER_IP, &cliaddr.sin_addr) <= 0 )
{
perror("INET_PTON() error");
exit( EXIT_FAILURE );
}
if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("SOCKET error");
exit( EXIT_FAILURE );
}
if( connect(sockfd, (struct sockaddr*) &cliaddr, sizeof(struct sockaddr)) < 0 )
{
perror("CONNECT() error :\\ ");
exit( EXIT_FAILURE );
}
pthread_create( &tid_send, NULL, &send_function, (void *) sockfd );
pthread_create( &tid_recv, NULL, &recv_function, (void *) sockfd );
pthread_join( tid_send, NULL);
pthread_join( tid_recv, NULL);
return 0;
}
static void* send_function( void* sockfd )
{
int i;
char arrc[ARRSIZE] = "This is from client-side\n";
int connfd = (int) sockfd;
/* poll() preparation */
struct pollfd fd_array[FD_ARRSIZE];
int nready;
/* poll initialization */
fd_array[0].fd = connfd;
fd_array[0].events = POLLOUT;
for( i = 0; i != 1; ++i )
{
if( (nready = poll( fd_array, 1, -1 )) <= 0 )
{
perror("can not POLL()\n");
exit( EXIT_FAILURE );
}
if( fd_array[0].revents & POLLOUT )
{
if( send(connfd, arrc, strlen(arrc), 0) < 0 )
{
perror("SEND() error");
exit( EXIT_FAILURE );
}
}
if( --nready <= 0 )
{
break;
}
}
return (NULL);
}
static void* recv_function( void* sockfd )
{
char arrc[ARRSIZE];
int connfd = (int) sockfd;
/* poll() preparation */
struct pollfd fd_array[FD_ARRSIZE];
int nready;
/* poll initialization */
fd_array[0].fd = connfd;
fd_array[0].events = POLLIN;
for( ; ; )
{
if( (nready = poll( fd_array, 1, -1 )) <= 0 )
{
perror("can not POLL()\n");
exit( EXIT_FAILURE );
}
if( fd_array[0].revents & POLLIN )
{
if( recv(connfd, arrc, ARRSIZE, 0) < 0 )
{
perror("RECV() error");
exit( EXIT_FAILURE );
}
printf("%s\n", arrc);
}
if( --nready <= 0 )
{
break;
}
}
return (NULL);
}
--
www.lispmachine.wordpress.com
my email is @ the above blog
check the "About Myself" page
.
- Follow-Ups:
- Re: echo client using threads
- From: arnuld
- Re: echo client using threads
- From: David Schwartz
- Re: echo client using threads
- Prev by Date: unix information
- Next by Date: Re: echo client using threads
- Previous by thread: unix information
- Next by thread: Re: echo client using threads
- Index(es):
Relevant Pages
|