tags:

views:

35

answers:

2

hi..

I am wanting my TCP server and client to "talk" to each other depending on what the other says. But when I run, it seems to go through one iteration, but then both the server and client seem to just "hang" there. Once I kill it on the client side, I end up getting a broken pipe error.

Can anyone interpret what I am doing wrong here?

SERVER code snippet:

while(feof(file_ptr) == 0)
{
    fscanf(file_ptr, "%s", supplies);
    printf("%s\n", supplies);

    //SEND supplies to all clients (currently just one client)

    n = write(newsockfd, supplies, strlen(supplies));

    if (n < 0)
    {
        error("ERROR writing to socket");
    }


    //Receive a request from client that they can use supply

    bzero(buffer,2);
    n = read(newsockfd,buffer,2);

    if (n < 0)
    {
        error("ERROR reading from socket");
    }

    printf("Who is using supply? %s\n", buffer);


    if(strcmp(buffer, "A"))
    {
        aRounds++;  
    }


    while(done != 1)
    {
        //WAIT loop until message CO is received from client
        bzero(buffer,2);
        n = read(newsockfd,buffer,2);

        if (n < 0)
        {
            error("ERROR reading from socket");
        }

        printf("Done? %s\n", buffer);



        if(strcmp(buffer, "CO"))
        {
            done = 1;
        }
    }

    done = 0;
}

fclose(file_ptr);
n = write(newsockfd, "DN", 2);

CLIENT code snippet:

while(noSupplies != 1)
{
    //RECEIVE MSG from server about supplies
    bzero(buffer,2); 
    n = read(sockfd,buffer,2);

    if (n < 0) 
    {
        error("ERROR reading from socket");
    }

    printf("%s\n",buffer);

    if(strcmp(buffer, "BC") == 0 || strcmp(buffer, "CB") == 0)
    {
        //SEND server msg that you are using supply

        n = write(sockfd,"A", 1);
        if (n < 0)
        {
            error("ERROR writing to socket"); 
        }


        printf("Client A has received components %s during round %d.\n", buffer, round);


        n = write(sockfd,"CO", 2);
        if (n < 0)
        {
            error("ERROR writing to socket"); 
        }

    }
    else if(strcmp(buffer, "DN"))
    {
        noSupplies = 1;
    }

    round++;
}

I get the following from the server (before killing):

BC
Who is smoking? A
Done smoking? CO

And the following from the client (before killing):

BC
Client A has received components BC during round 1.

Then after killing from the client.. I get the following from the server:

BC
Who is using supply? A
Done? CO
Done? 
CB
Who is using supply? 
Done? 
CB
Who is using supply? 
Done? 
BC
Broken pipe

Does anyone understand what I am doing wrong? (looking for code fix!)

Just an FYI.. I will be changing the server code eventually to handle listening to mulitple clients (TCP) but one hurdle at a time right? :S

Thanks!

+1  A: 

Not sure if this is all of your problem, but

bzero(buffer, 2);
n = read(socket, buffer, 2);

...

printf("%s", buffer);

is not correct, since if the read actually did get 2 bytes and neither of them were 0 then buffer may not be a null terminated string (unless there is something earlier that made that so).

Several calls to strcmp should also always fail for the same reason -- the read in string is not 0 terminated so strcmp thinks that it keeps on going and therefore is not the same as the compared to string, even if the first letters are the same.

edit

 n = read(socket, buffer, 2);
 if (n<0) {
     die_horrible_death();
 }
 buffer[n] = 0; // since arrays are 0 indexed this should be after last read character
 printf("I just read: \"%s\"\n", buffer);
nategoose
so you are saying that buffer needs to be a null terminating string?
developer
If you want to treat it like a C string, the way that `printf` and `strcmp` do then yes, you need to make sure that the character after the last character that you have read in is set to 0. I am not sure if this will fix your problem because I don't really have much of an idea what it is supposed to do.
nategoose
Ok so I changed all cases where I was writing to have \n at the end and increased the size sent by one. and increased all the read sizes by 1. e.g. n = write(sockfd,"CO\n", 3); and bzero(buffer, 3);n = read(socket, buffer, 3); Changing this seemed to fix my problem!! :) Were all the changes necessary or just on the reads?
developer
'\n' is a newline, not a 0. See example in edit.
nategoose
hmm.. adding buffer[n] = 0; does not help at all, but once I changed everything to send a new line after the string it stopped "hanging" and completed the program as expected...
developer
I am confused about why that would have changed anything (especially on the TCP side of things, though maybe on the stdout printing side of things), but I'm glad that it works for you now. You should read what valdo said in their answer about data not coming in one read/recv call. Relying on that is the kind of thing that makes programs work sometimes and fail other times for what appears to be no good reason.
nategoose
A: 

Your server code writes only once something to the client, at the beginning. Later, in the loop - it just reads.

OTOH your client reads and writes in the loop.

Since you're working with sockets in a blocking mode - this means that your client eventually will become blocked in a call to recv.

P.S. No offenses - but you have a lot to learn.

  1. TCP is a tunnel. When your server sends 2 bytes of data in a single call to send/write - there's no guarantee your client will read this within a single call to recv.
  2. Hence - reading and parsing always must be done in a sort of a loop.
  3. You can't write a really robust client/server with ability to timeout/interrupt on demand using only blocking I/O.
  4. Learn, learn, learn
valdo
thanks for your comments! I am learning! hence why this is a practice program! I actually fixed it by putting /n characters whenever I write something :D
developer
oh and yes, it is only supposed to write once at the beginning and just listen for two responses in order to continue :)
developer
Well, I meant that when you're using blocking I/O - you actually loose the control over the program flow. You become dependent on the peer. Unless it sends anything to you - you're blocked. Hence - it's better to use sockets asynchronously
valdo
I see.. well it will always send something because of the contents in the textfile. And once I add new clients and a different textfile, there will always be someone who will reply.. so for my next example I will take your advice and try it asynchronously :)
developer
Yes, it is possible to write a robust client/server with ability to interrupt and timeout, using blocking I/O. Just use select().
Alek
Not exactly. You may prevent getting blocked on recv in you call 'select' before to ensure there's a read available on the socket. However you may still become blocked when you send something on the socket (if its send buffer is full). To avoid this you **must** set the socket to the non-blocking mode, regardless to select
valdo