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?
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?
> 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.
>>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]
>> 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; }
>>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
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; }
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
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.
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]