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?
Printable View
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 ( 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).
>> 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;
}
>>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.
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 );
}
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);
}