Re: echo client/server give problems if array sizes are different



On Jun 11, 12:17 pm, Brice Rebsamen <brice.rebsa...@xxxxxxxxx> wrote:
On Jun 5, 6:08 pm, David Schwartz <dav...@xxxxxxxxxxxxx> wrote:



On Jun 5, 2:34 am, arnuld <sunr...@xxxxxxxxxxxxxxxx> wrote:

char arrc[ARRSIZE];
memset( arrc, '\0', strlen(arrc) );

First bug. In the call to memset, 'arrc' contains random junk. It does
not contain a C-style string yet. Why do you pass it to 'strlen'?

while( (recv_flag = recv( sockfd, arrc, BUFFSIZE, 0)) != -1 )
{
printf("\n---------------:: %s\n", arrc);

At this point, 'arrc' contains some random bytes you received. It does
not contain a C-style string yet. Why do you try to print it with
'%s'?

if( send(sockfd, arrc, BUFFSIZE, 0 ) == -1 )

At this point, recv_flag contains the number of bytes received. Why
are you passing some other number to 'send' as the number of bytes to
send?

I remember you saying your program would receive a *line* and then
send a *line*? Where's the code to check when you have a line? Did you
forget to actually implement your protocol completely?!

/* a simple client to send a string to server
* and then recieving same string back.

Ahh, it's a string, not a line? Which is it? Take a step back and
define your protocol with a specification. Otherwise, when you have
problems like this, it's impossible to know what's right.

char arrc[ARRSIZE];
memset( arrc, '\0', strlen(arrc) );

Same bug. Do you know the difference between an array of characters
and a string? (The answer: a string must end with a 0 bytes.) At this
point 'arrc' is not a string (nobody put any zero byte anywhere), so
it is an error to pass it to 'strlen'.

while( fgets(arrc, ARRSIZE, stdin) )
{
if( send( sockfd, arrc, ARRSIZE, 0 ) == -1 )

Whoa! You only want to send the bytes you got from 'fgets'. Not the
whole array!

if( recv( sockfd, arrc, ARRSIZE, 0) == -1 )
{
fprintf(stderr, "RECV() error!\n");
exit( EXIT_FAILURE );
}

fputs( arrc, stdout );

You receive some number of bytes into 'arrc', you have no idea how
many. You do not have a C-style string, since there's no terminating
zero byte. You *cannot* pass this to 'fputs'.

It looks like three classic errors:

1) A use of TCP without designing and specifying a protocol on top of
TCP.

2) A use of TCP with an assumption that bytes of data are somehow
glued together by TCP. (This is why you need '1', because they're
not.)

3) A consistent confusion between arrays of characters of known length
and C-style strings.

DS
2) A use of TCP with an assumption that bytes of data are somehow
glued together by TCP. (This is why you need '1', because they're
not.)

The bytes may arrive in small chunks so you have to repeat the read
call until all bytes are here. Meaning that you should check for a
termination character, i.e. '\0'. TCP guarantees that packets all
arrive in the right order but doesn't guarantee that a message arrive
in one chunk (even if small messages might very often arrive in one
chunk).



I tried to modify the posted code to create a multi threaded server
instead of a multi processed one (see code below). However I don't
understand why when one of the clients exits (CTRL-C) it also kills
the server.


Here is a code for the server part.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

#define SERVER_IP "127.0.0.1"

#define BUFFSIZE 101
#define MAX_CONNECTION 25

void *echo_back( void * );

int main( int argc, char** argv )
{
int server_fd, accept_fd, my_port;
struct sockaddr_in servaddr;
pthread_t tid;

memset( &servaddr, '\0', sizeof(servaddr) );

if( argc == 2 )
{
my_port = atoi( argv[1] );
}
else
{
fprintf( stderr, "USAGE: ./file PORT\n");
exit( EXIT_FAILURE );
}

servaddr.sin_family = AF_INET;
servaddr.sin_port = htons( my_port );
inet_aton( SERVER_IP, &(servaddr.sin_addr) );

if( -1 == (server_fd = socket(PF_INET, SOCK_STREAM, 0)) )
{
fprintf( stderr, "SOCKET() error\n" );
exit( EXIT_FAILURE );
}

if( -1 == bind( server_fd, (struct sockaddr*) &servaddr,
sizeof( struct sockaddr )) )
{
fprintf( stderr, "BIND() error\n" );
exit( EXIT_FAILURE );
}
printf("bind()\n");

if( -1 == listen( server_fd, MAX_CONNECTION ))
{
fprintf( stderr, "LISTEN() error\n" );
exit( EXIT_FAILURE );
}
printf("listen()\n");

/* now lets see what client has to say */
for( ; ; )
{
if( (accept_fd = accept(server_fd, 0, 0)) == -1 )
{
fprintf( stderr, "ACCEPT() error\n" );
exit( EXIT_FAILURE );
}
printf( " accept()\n");

if( pthread_create(&tid,0,echo_back,&accept_fd)!=0 )
{
fprintf( stderr, "pthread_create() error\n" );
exit( EXIT_FAILURE );
}
printf( " pthread_create()\n");

}

return 0;

}

void * echo_back( void* sockfd_ )
{
int nBytes, sockfd;
char arrc[BUFFSIZE];

sockfd = *((int *)sockfd_);
memset( arrc, '\0', BUFFSIZE );

while( (nBytes = recv( sockfd, arrc, BUFFSIZE, 0)) != -1 )
{
if( nBytes==0 )
continue;

printf("\n---------------:: %s\n", arrc);
if( send(sockfd, arrc, BUFFSIZE, 0 ) == -1 )
{
fprintf( stderr, "SEND() error\n" );
close(sockfd);
return NULL;
}
memset( arrc, '\0', BUFFSIZE );
}

if( nBytes == -1 )
{
fprintf( stderr, "RECV() error\n" );
close(sockfd);
return NULL;
}
return NULL;
}



Here is the client part (same as above, except that I fixed the usage
of string arrays)

/*
* A simple client to send a string to server
* and then recieving same string back.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MY_SERVER "127.0.0.1"
#define BUFFSIZE 101

int main( int argc, char** argv )
{
int sockfd, MY_PORT;
struct sockaddr_in client_str;
char arrc[BUFFSIZE];
memset( arrc, '\0', strlen(arrc) );

if( argc == 2 )
{
MY_PORT = atoi( argv[1] );
}
else
{
fprintf(stderr, "I expect the port number as argument\n");
exit( EXIT_FAILURE );
}

if( (sockfd = socket( PF_INET, SOCK_STREAM, 0 ) ) == -1 )
{
fprintf(stderr, "SOCKET ERROR: can not create socket\n");
exit( EXIT_FAILURE );
}

client_str.sin_family = AF_INET;
client_str.sin_port = htons(MY_PORT);
client_str.sin_addr.s_addr = inet_addr( MY_SERVER );
memset( client_str.sin_zero, '\0', sizeof( client_str.sin_zero ) );

if( connect( sockfd, (struct sockaddr*) &client_str, sizeof( struct
sockaddr)) == -1 )
{
fprintf(stderr, "CONNECT() error\n");
exit( EXIT_FAILURE );
}

while( fgets(arrc, BUFFSIZE, stdin) )
{
if( send( sockfd, arrc, strlen(arrc), 0 ) == -1 )
{
fprintf(stderr, "SEND() error!\n");
exit( EXIT_FAILURE );
}

memset( arrc, '\0', BUFFSIZE );

if( recv( sockfd, arrc, BUFFSIZE, 0) == -1 )
{
fprintf(stderr, "RECV() error!\n");
exit( EXIT_FAILURE );
}

fputs( arrc, stdout );
memset( arrc, '\0', BUFFSIZE );
}

return 0;

}

.



Relevant Pages

  • Re: echo client/server give problems if array sizes are different
    ... In the call to memset, 'arrc' contains random junk. ... not contain a C-style string yet. ...
    (comp.unix.programmer)
  • Re: Ein bisschen Assembler
    ... EAX für FloatToDecimal -> Digits ... current_variable: String; ... : expr { ...
    (de.comp.lang.delphi.misc)
  • Re: Excel ActiveX TextBox Question
    ... You can use the Exit event to test whether the user should be allowed ... Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean) ... Then test the state of the SHIFT key: ... process the full string after the user hits "Enter". ...
    (microsoft.public.excel.misc)
  • RE: System.Diagnostics.Process() hangs
    ... you redirected output & input, then did a wait for task exit. ... exit until it writes its output, which you won't read until it exits. ... public string CreateTSUser ... SecureString securePass = new SecureString; ...
    (microsoft.public.dotnet.framework.aspnet)
  • Re: Parse String
    ... it picking up substrings beginning with 'f' followed by hyphens, ... Function gnaf(s As String) As Variant ... Exit Do 'inner Do ... Loop ...
    (microsoft.public.excel.programming)