0
//server side
void* s2(void *arg){
    info *s = (info*)arg;
    char buffer[MAXS];
    int k;
    sockaddr_in addr;
    socklen_t aSize = sizeof(sockaddr_in);
    int sfd = accept(s->fd,(sockaddr*)&addr,(socklen_t*)&aSize);
    if(sfd<0){
        s->current--;
        pthread_exit(0);
    }
    while(1){
        k = recv(sfd,buffer,MAXS,0);
        cout<<buffer<<"\n";
        //1. k ==0 socket has been closed by client 
        //2. k==-1 error in recv 
        //3. recv quit
        if((k==-1)||(!strncmp(buffer,"quit",4))||(k==0))break; 
        sprintf(buffer,"%d\n",(int)strlen(buffer)); //Convert length to  string using sprintf()
        send(sfd,buffer,strlen(buffer),0); //send buffer to client 
    }
    close(sfd);
    if(s->limit==s->current)
    FD_SET(s->fd,&sfds);
    s->current--; //decrement the client number 
    pthread_exit(0);
}

//client side
1. send(sockfd,"sadhdag",8,0);
2. send(sockfd,"ss",3,0);

Server recv sadhdag in first call to recv .

In second call to recv server recv

ss
dag

server side:

function s2 is run by a thread and argument is passed with socket information connection is accepted there and send and recv is called on newly accepted client.

Why this is happening ? or how to avoid this ?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
sonus21
  • 5,178
  • 2
  • 23
  • 48
  • Can you post the actual code block in server which does two `recv()` calls? – Karthik Kalyanasundaram Feb 26 '15 at 03:28
  • 1
    immediate solution would be to `memset` the `buffer` to 0, before every `recv` call. `memset(buffer, 0, MAXS)`. – Karthik Kalyanasundaram Feb 26 '15 at 03:41
  • @KarthikKalyanasundaram why we need to do this ? – sonus21 Feb 26 '15 at 03:45
  • `memset` will reset the data your `buffer` holds now (ie. erases the previously read data). As per your code, you don't need call to `memset` as after 2nd `recv` your `buffer` should look like this `|s|s|\0|h|d|a|g|\0|` and when you do a cout< – Karthik Kalyanasundaram Feb 26 '15 at 03:54
  • You are not null-terminating the buffer. – mark4o Feb 26 '15 at 03:54
  • @KarthikKalyanasundaram but this prints entire string as i mentioned . – sonus21 Feb 26 '15 at 03:56
  • @sonukumar If you use Visual Studio, can you just check the content in buffer using Quick Watch and ensure that your buffer has '\0' after 'S', 'S' – Karthik Kalyanasundaram Feb 26 '15 at 03:57
  • @mark4o - that is what I initially suspected but from client he sends null terminated string `send(sockfd,"ss",3,0)`, he sends 3 bytes and I hope this should send null terminator too. – Karthik Kalyanasundaram Feb 26 '15 at 03:58
  • @KarthikKalyanasundaram No. You tell it to send 3 bytes: it sends 3 bytes. Null termination of strings is a C-ism. It has nothing to do with sockets. – user207421 Feb 26 '15 at 04:22
  • @EJP when you say "ss" (as per my understanding), it already includes `\0` at the end. When you say send 3 bytes it should send `|s|s|\0|` – Karthik Kalyanasundaram Feb 26 '15 at 05:05
  • @KarthikKalyanasundaram It sends 3 bytes, but because you said 3 bytes, not because it's obeying any trailingn-null rule. If you told it to send 4 it would send 4, the two 'a's, the null, and whatever was next in memory. – user207421 Feb 26 '15 at 05:08
  • @EJP Ok. What I am wondering is if client sends 3 bytes with data `|S|S|\0`, `recv` should also receive the same data right? and data in the `buffer` after `recv` call should have been `|s|s|\0|....` – Karthik Kalyanasundaram Feb 26 '15 at 12:16

2 Answers2

3

You're ignoring the count returned by recv(). Contrary to suggestions in comments, it isn't necessary to memset() the buffer to zero before recv(), but it is necessary to only use that buffer afterwards up to that count. For example:

printf("%s", buffer);

is wrong, and

printf("%.*s", count, buffer);

is right.

NB

if((k==-1)||(!strncmp(buffer,"quit",4))||(k==0))break;

isn't correct either. It should be

if((k==-1)||(k==0)||(k >= 4 && !strncmp(buffer,"quit",4))) break;

It isn't valid to look into the buffer at all unless k is positive, and it isn't valid to compare four characters in it unless there are four characters in it.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

You forgot to actually implement any kind of protocol or application-level logic of any kind. This sums it up:

    k = recv(sfd,buffer,MAXS,0);
    cout<<buffer<<"\n";

This code suggests you're terminating your messages with a newline:

    sprintf(buffer,"%d\n",(int)strlen(buffer)); //Convert length to  string using sprintf()
    send(sfd,buffer,strlen(buffer),0); //send buffer to client 

If so, where's the code to parse that on the other end? You throw the returned length away, so you wouldn't even know which characters to check for a newline.

TCP is a byte-stream protocol that does not preserve application-level message boundaries. If you want to use it to send strings or other application-level messages, you have to specify and implement an application-level protocol to do it.

You call recv to get the raw TCP data, then you output it as if it was a string. If you're going to define and implement a protocol to send and receive strings over TCP, you have to actually do it. You can't just imagine it happens by magic.

If you want to receive newline-terminated messages into C-style strings, you can certainly do it. But you have to actually write the code to do it.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Can you add links or references for Application-level logic design , implementation , best practice e.t.c. ? – sonus21 Feb 27 '15 at 08:45