Re: Learnign select()
- From: K-mart Cashier <cdalten@xxxxxxxxx>
- Date: Mon, 16 Jun 2008 20:40:12 -0700 (PDT)
On Jun 16, 6:47 pm, Barry Margolin <bar...@xxxxxxxxxxxx> wrote:
In article <g353th$js...@xxxxxxxx>, arnuld <sunr...@xxxxxxxxxxxxxxxx>
wrote:
STATEMENT: I have created a TCP echo server-client pair where client
sends some text to server and then server sends back the same text to
client and then client prints it onto the screen.
PROBLEM #1: I can't understand the select() :(
PROBLEM #2: I have edited my server program to use select() and it has no
compilation or run-time errors but when it runs then server hangs there
infinitely consuming all of the CPU.
If a program hangs in select() it shouldn't use any CPU time. So I
suspect it's looping after select() returns, not hanging in select()
itself.
There are some problems in your code that I've annoted below.
Down here you will find the code for both server and client. I am using
Unp vol-1 by Stevens but still can't understand how the select is
implemented in code . any pointers ? . So far I understand only this:
You seem to be using it correctly. You even did something right that
most beginners get wrong -- your use of rdset and rdset2. Most
first-time select() users don't realize they have to re-initialize the
fdset every time through the main loop.
-- * --
select() works as a 3rd party which sits between different clients and
single server. It checks to see of the client connection (FD) is ready
for reading and when it is then it gives that connection to the server.
Hence it does not do any communication by itself, It just acts as medium
between server and clients and its main purpose is to keep server
unblocked all the time.
-- * --
-------------- server code ---------------
/* A server handeling multiple client using select which in fact
a single-tasking mechanism and I always thought select is a
replacement for a multi-tasking mechanism :-O
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_IP "127.0.0.1"
enum { ARRSIZE=101, BACKLOG=10 } ;
int main( int argc, char** argv )
{
int i, j;
int server_fd, accept_fd;
int servport;
struct sockaddr_in servaddr, cliaddr;
socklen_t cliaddr_len;
char arrc[ARRSIZE];
/* preparation for select() */
int maxrank_fd; /* used with select() */
int max_idx; /* maximum index into the array */
int arrfd[FD_SETSIZE];
fd_set rdset, rdset2;
int nready, sockfd;
if( argc != 2 )
{
fprintf(stderr, "USAGE: ./file PORT\n");
exit( EXIT_FAILURE );
}
else
{
servport = atoi( argv[1] );
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons( servport );
inet_aton( SERVER_IP, &(servaddr.sin_addr) );
memset( &servaddr.sin_zero, '\0', sizeof( servaddr.sin_zero ) );
if( -1 == (server_fd = socket(AF_INET, SOCK_STREAM, 0)) )
{
perror("SOCKET() error");
exit( EXIT_FAILURE );
}
if( -1 == bind(server_fd, (struct sockaddr*) &servaddr, sizeof
(servaddr)) )
{
perror("BIND() error");
exit( EXIT_FAILURE );
}
if( -1 == (listen(server_fd, BACKLOG)) )
{
perror("LISTEN() error");
exit( EXIT_FAILURE );
}
/* select comes into play after listen() and before accept() */
maxrank_fd = server_fd;
max_idx = -1;
/* initialize the array of client FDs */
for( i=0; i < FD_SETSIZE; ++i )
{
arrfd[i] = -1;
}
/* initilaize the FD set
it will connect select() with the server)_fd we created */
FD_ZERO(&rdset);
FD_SET( server_fd, &rdset );
/* apply & use select() */
for( ; ; )
{
/* copy the set. older ones will be used later */
rdset2 = rdset;
nready = select( maxrank_fd + 1, &rdset2, NULL, NULL, NULL );
if( FD_ISSET(server_fd, &rdset2) )
{
cliaddr_len = sizeof( struct sockaddr_in);
if( -1 == (accept_fd = (accept(server_fd, (struct sockaddr*)
&cliaddr, &cliaddr_len))) )
{
perror( "ACCEPT() error");
exit( EXIT_FAILURE );
}
for( j=0; j < FD_SETSIZE; ++j )
{
if( arrfd[j] < 0 )
{
arrfd[j] = accept_fd;
break;
}
}
/* check if arrfd is full */
if( j == FD_SETSIZE )
{
perror("Server Overloaded with too many connections.
\nPlease connect later");
exit( EXIT_FAILURE );
}
/* add the accept() descriptor to the old set */
FD_SET( accept_fd, &rdset );
if( accept_fd > server_fd )
{
maxrank_fd = accept_fd;
}
if( j > max_idx )
{
max_idx = j;
}
if( --nready <= 0 )
{
continue;
}
}
/* we can use the useless i from one earlier loop */
for( i=0; i < max_idx; ++i )
{
if( (sockfd = arrfd[i]) < 0 )
{
continue;
}
if( FD_ISSET(sockfd, &rdset2) )
{
if( -1 == (recv(accept_fd, arrc, ARRSIZE, 0)) )
You have to read from sockfd, not accept_fd.
{
perror( "READ() error");
exit( EXIT_FAILURE );
}
if( -1 == (send(accept_fd, arrc, ARRSIZE, 0)) )
You have to write to sockfd, not accept_fd.
You shouldn't send ARRSIZE bytes, you should send the number of bytes
that recv() returned. Unfortunately, you didn't save that anywhere.
{
perror( "READ() error");
This should be "SEND() error".
exit( EXIT_FAILURE );
}
}
if( --nready <= 0 )
This should be inside the if(FD_ISSET(sockfd, &rdset2)) block.
{
break;
}
}
}
return 0;
}
------------- client code -------------
I haven't looked at the client code, but I wouldn't be surprised if it
has problems like the ones I noticed in the server.
/* A client to send a string to a server handeling multiple-clients using
slect
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_IP "127.0.0.1"
enum { ARRSIZE=101 } ;
int main( int argc, char** argv )
{
int conn_fd, conn_port;
struct sockaddr_in cliaddr;
char arrc[ARRSIZE] = "Spanish Eyes\n";
if( 2 == argc )
{
conn_port = atoi(argv[1]);
}
else
{
fprintf(stderr, "USAGE: ./file PORT\n");
exit( EXIT_FAILURE );
}
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(conn_port);
inet_pton( AF_INET, SERVER_IP, &cliaddr.sin_addr );
memset( &cliaddr.sin_zero, '\0', sizeof(cliaddr.sin_zero) );
if( -1 == (conn_fd = socket(PF_INET, SOCK_STREAM, 0)) )
{
perror("SOCKET() error");
exit( EXIT_FAILURE );
}
if( -1 == (connect(conn_fd, (struct sockaddr*) &cliaddr, ARRSIZE)) )
{
perror("CONNECT() error");
exit( EXIT_FAILURE );
}
if( -1 == (send(conn_fd, arrc, ARRSIZE, 0)) )
{
perror("SEND() error");
exit( EXIT_FAILURE );
}
if( -1 == (recv( conn_fd, arrc, ARRSIZE, 0)) )
{
perror("RECV() error");
exit( EXIT_FAILURE );
}
printf("---------------\n%s\n", arrc);
return 0;
}
[arnuld@dune ~]$
--
Barry Margolin, bar...@xxxxxxxxxxxx
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***- Hide quoted text -
- Show quoted text -- Hide quoted text -
- Show quoted text -
Is there some kind of trick to finding the errors right away in a
piece of code? Or does this just from experience?
Chad
.
- References:
- Learnign select()
- From: arnuld
- Re: Learnign select()
- From: Barry Margolin
- Learnign select()
- Prev by Date: Re: Unable to resolve the symbols in a shared library
- Next by Date: Re: Learnign select()
- Previous by thread: Re: Learnign select()
- Next by thread: Re: Learnign select()
- Index(es):
Relevant Pages
|