recv/send

This is a discussion on recv/send within the Networking/Device Communication forums, part of the General Programming Boards category; do recv and send automatically put a '

Thread: recv/send

'at the end of the string it sends? and I always use the ...

  1. #1
    Registered User
    Join Date
    Oct 2003
    Posts
    17

    recv/send

    do recv and send automatically put a '\0'at the end of the string it sends?
    and I always use the same string as a parameter, should I clear the string before I do the recv or send?

  2. #2
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,673
    > do recv and send automatically put a '\0'at the end of the string it sends?
    No - they work purely on the length parameter you supply to these routines
    send() will only send n bytes
    recv() will receive at most n bytes

    > should I clear the string before I do the recv or send?
    Not necessary

    // the -1 allows for adding a \0 when recv() fills the buffer
    n = recv( sock, buff, sizeof(buff)-1, 0 );

    // if recv() succeeded, then add a \0
    if ( n > 0 ) buff[n] = '\0';
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >>if ( n > 0 ) buff[n] = '\0';
    You are of course assuming that you got a complete string in one read.

    For the OP: Remember that TCP/IP is a byte streaming protocol, meaning when you recv() once, you're not guaranteed to receive everything that was sent.

    For example, if the other end sends the word hello followed by a \0 byte (totaling 6 bytes), it is theoretically possible that you will only get one byte at a time when you call recv(). So, in this case, 6 calls to recv() will get you all the data. This is an extreme example, in reality, using data that small you're highly likely to get all 6 bytes in one go, but large strings will be split, particularly is they exceed the network packet size (MTU - Maximum Transfer Unit).
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> You are of course assuming that you got a complete string in one read.

    Still, null-terminating a partial read is harmless and is required in fact if you're going to use strcat() for instance to build the buffer (as opposed to more manual methods). Kind of restating what Hammer already said, the buffer you use for recv() is not usually going to be the one that the final message is stored in. I'll give an example.

    Code:
    // NOTE: untested
    int receive(SOCKET sock, char message[], int max)
    {
     int total = 0;
     const int bsize = 1024;
     char buffer[bsize+1];
     int read = bsize;
     
     message[0] = 0; // initialize for strcat()
    
         while(read == bsize) 
       {
          read = recv(sock, buffer, bsize);
          if(read < 0) return -1; // error, bail out
          total += read;
          if(total > max)  return -2; // overflow
          buffer[read] = 0;
          strcat(message, buffer);
        }
         
     return total;
    }
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  5. #5
    Registered User
    Join Date
    Oct 2003
    Posts
    17
    >>total += read;
    does it mean total=total+read?

    I can send/receive strings both ways between my client and my server
    but now, I want to send the content of one (text) file from my client to my server and save it on my server
    I don't even know how to begin
    could you help me

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Well then post the code you have.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  7. #7
    Registered User
    Join Date
    Oct 2003
    Posts
    17
    ok here's what I've done so far
    this is not my real source code, just a program specifically designed to test exchanges between a client and a server

    server:
    Code:
    main(){
    	char string[STRGLEN], length[STRGLEN], text[STRGLEN];
    	int fromlen;
    	char hostname[64]; /* local machine hostname */
    	struct hostent *hp; /* gethostbyname return ptr */
    	register int s; /* socket descriptor, or -1 if error */
    	register int ns; /* created new socket for accept */
    	struct sockaddr_in  sin; /* socket structure */
    	struct sockaddr_in fsin; /* socket str. for accept*/
    	float number=0.0;
    	int i;  /* loop counter */
    	int selection;	/* menu choice */
    	int num_user, nRecv, nSend;
    	userslist* ulist;
    	fileslist* flist;
    	userknot* str_userknot;
    	char ch;
    	FILE* p;
    	
    	/* first need to know our hostname. */
    	gethostname(hostname, sizeof(hostname));
    	
    	/* Next look up the network address of our host.*/
    	if((hp = gethostbyname(hostname)) == NULL){ 
    		fprintf(stderr, "%s: unknown host\n", hostname);
    		exit(1); 
    	}
    	
    	/* create socket in Internet domain(AF_INET), that is 
    	connection oriented (SOCK_STREAM) rather than
    	connectionless (SOCK_DGRAM),
    	arg3=0 for default TCP/IP protocol*/
    	if(( s = socket(AF_INET, SOCK_STREAM, 0) ) < 0){ 
    		perror("server: socket"); 
    		exit(1); 
    	}
    	
    	/* Create the address to connecting to. We use port
    	APORT but put it into network byte order.
    	Also we use bcopy to copy the network number. */
    	bzero(&sin, sizeof(sin));
    	sin.sin_family = AF_INET;  /* IP protocol */
    	/* sin.sin_addr.s_addr = INADDR_ANY;*/
    	sin.sin_port = htons(APORT);
    	bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
    	
    	/* Try to bind(address and port no.)to socket s */
    	if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){ 
    		perror("server: bind"); 
    		exit(1); 
    	}
    	
    	/* server ready, listen on socket s max 5 requests queued*/
    	if(listen(s, 5) < 0) {
    		perror("server: listen"); 
    		exit(1); 
    	}
    
     
    
       /* Accept connections then fork ns (new socket) that
       will be connected to the client. fsin will contain
       the IP address of the client. */
    	bzero(&fsin, sizeof(fsin));
    	fromlen = sizeof(fsin);
    	if((ns = accept(s, (struct sockaddr *)&fsin, &fromlen))<0){
    		perror("server: accept"); 
    		exit(1);
    	}
    
    	strcpy(string,"essai.txt");
    	p=fopen(string,"r");
    	i=0;
    	ch = getc(p);  /* read 1st character in file */
    	while( ch != EOF){ /* keep going until end of file */
    		text[i]=ch;
    		ch = getc(p);  /* read next character in in-file */
    		i++;
    	}
    	fclose(p);
    	text[i]='\0';
    	send(ns, text, i, 0);
    	
    	
    	/* We can simply use close() to terminate the
    	connection, since we're done with both sides */
    	close(s);
    }

    client:
    Code:
    main(int argc, char *argv[]){  /* argv[1] is server hostname */
    	char string[STRGLEN];  /* message string */
    	register int s;   /* created socket (index to unix descriptor table) */
    	struct hostent *hp;  /* pointer to host structure */
    	struct sockaddr_in sin;  /* socket structure */
    	float number;
    	int i, n;   /* loop counter */
    	int selection;	/* menu choice */
    	
    	/*  look up the network address of server hostname */
    	hp = gethostbyname(argv[1]);
    	if( hp==0 ){ 
    		fprintf(stderr, "unknown host %s\n", argv[1]);
    		exit(1);
    	}
    	
    	/* create socket in the Internet domain(AF_INET) that will
    	be connection oriented SOCK_STREAM. (connectionless is 
    	SOCK_DGRAM) 3rd argument indicated default TCP/IP protocol */
    	if( (s = socket(AF_INET, SOCK_STREAM, 0)) <0 ){
    		perror("client: socket");
    		exit(1);
    	}
    	
    	/* Create the address we will be connecting to We use port
    	1234 but put it into network byte order.
    	Also we use bcopy to copy the network number */
    	sin.sin_family = AF_INET;
    	sin.sin_port = htons(APORT);
    	bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
    
     
    
       /* Try to connect to the address.
       For this to succeed, the server must already have bound
    	this address, and must have issued a listen() request. */
    	if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){ 
    		perror("client: connect");
    		exit(1); 
    	}
       
    	n=recv(s, string, STRGLEN, 0);
    	printf("client: n=%d\n", n);
    	printf("client: %s\n", string);
     
    
       /* close connection, since were finished on both sides */
    
       close(s);
    
    }

    I'm using getc but I'm not sure it is the best way. I suppose I should use fgets but I don't know how to keep reading the file until EOF
    also there is the problem of the file's length: I'm putting my whole file in a string of fixed length but in reality I don't know the file's length. It could be 10 as well as 10000. How can I fix that?
    and of course there is the problem you mentionned just before: if my file is very long, the client could get the string in more than just one read. I have yet to try the code you provided. I've just put aside this aspect for the moment

  8. #8
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,673
    Sender, sending 1 line at a time

    Code:
    p = fopen("essai.txt","r");
    while ( fgets( text, sizeof text, p ) != NULL ) {
        send(ns, text, strlen(text), 0);
    }
    fclose( p );

    Receiver, receiving whatever comes our way
    Code:
    while ( (n=recv(s, string, STRGLEN-1, 0)) > 0 ) {
        string[n] = '\0';
        printf( "%s", string );
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  9. #9
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Just for fun, here are some more robust recv style functions. They're taken from this book, which I recommend you read if you're serious about this subject.

    The following code is from Effective TCP/IP Programming by Jon C. Snader, Copyright 2000 by Addison-Wesley.

    Code:
    /* readline - read a newline terminated record */
    int readline(SOCKET fd, char *bufptr, size_t len)
    {
      char        *bufx = bufptr;
      static char *bp;
      static int  cnt = 0;
      static char b[1500];
      char        c;
    
      while (--len > 0)
      {
        if (--cnt <= 0)
        {
          cnt = recv(fd, b, sizeof(b), 0);
          if (cnt < 0)
          {
            if (errno == EINTR)
            {
              len++;  /* the while will decrement */
              continue;
            }
    
            return(-1);
          }
    
          if (cnt == 0) return(0);
          bp = b;
        }
    
        c = *bp++;
        *bufptr++ = c;
        if (c == '\n')
        {
          *bufptr = '\0';
          return(bufptr - bufx);
        }
      }
    
      set_errno(EMSGSIZE);
      return(-1);
    }
    Code:
    /* readn - read exactly n bytes */
    int readn(SOCKET fd, char *bp, size_t len)
    {
      int cnt;
      int rc;
    
      cnt = len;
      while (cnt > 0)
      {
        rc = recv(fd, bp, cnt, 0);
    
        if (rc < 0)           /* read error? */
        {
          if (errno == EINTR) /* interrupted? */
            continue;         /* restart the read */
          return(-1);         /* return error */
        }
    
        if (rc == 0)          /* EOF? */
          return(len - cnt);  /* return short count */
        bp += rc;
        cnt -= rc;
      }
    
      return(len);
    }
    Code:
    /* readcrlf - read a CR/LF terminated line */
    int readcrlf(SOCKET s, char *buf, size_t len)
    {
      char  *bufx = buf;
      int   rc;
      char  c;
      char  lastc = 0;
    
      while (len > 0)
      {
        if ((rc = recv(s, &c, 1, 0)) != 1)
        {
          /*
           *  If we were interrupted, keep going,
           *  otherwise, return EOF or the error.
           */
          if (rc < 0 && errno == EINTR) continue;
          return(rc);
        }
    
        if (c == '\n')
        {
          if (lastc == '\r') buf--;
          *buf = '\0';  /* don't include <CR><LF> */
          return(buf - bufx);
        }
    
        *buf++ = c;
        lastc = c;
        len--;
      }
    
      set_errno(EMSGSIZE);
      return(-1);
    }
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21