tags:

views:

83

answers:

1

I’m having trouble with a simple TCP socket with the connect() and read() function. This program works if I start the server first, and the client second. However, when I start the client first, it continues to try to connect to the server, then when I start the server, it connects but the subsequent read returns 0 bytes. This suggests that the server closed the socket, but the debug statements do not support this.

I’m trying to have the client continually trying to connect to the server on port 6380, then read data. If the connection is lost, the client will try to reconnect again. I have SO_REUSEADDR set for the sockets. Is there something else that I'm missing?

Source Code for Server

//***** SERVER *****
#include <iostream>
#include "SocketAdapter.h"
#include "SocketServer.h"
#include <errno.h>
#include <string.h>

unsigned char buffer[] = "123123123";

int main()
{
   SocketAdapter  socket;
   SocketServer   server(6380);

   server.Start();
   std::cout << "Wait for Connection" << std::endl;
   server.WaitForConnection(socket);
   std::cout << "Start to Send Data" << std::endl;

   while(1)
   {
      std::cout << "Sending Data   ";
      int bytesSent = socket.Send(buffer, 10);
      std::cout << "byteSent = " << bytesSent << std::endl;
      if (bytesSent == -1)
      {
         std::cout << "Errno (" << errno << ") - " << strerror(errno) << std::endl;
      }

      sleep(1);
   }//end while

   std::cout << "Ending Server" << std::endl;
   socket.Close();

   return 0;
}

Source Code for Client

// ***** SIMPLE CLIENT ******
#include <iostream>
#include "SocketAdapter.h"
#include "SocketClient.h"
#include <string.h>
#include <errno.h>

int main()
{
   SocketAdapter  socket;
   SocketClient   client(6380, "127.0.0.1");

   unsigned char buffer[1024];


   while(1)
   {
      client.Start();

      //Loop till we connect to Server
      while( !client.Connect(socket) )
      {
         std::cout << "Trying to connect to server." << std::endl;
         sleep(1);
      }

      std::cout << "Connected to Server" << std::endl;

      //Read till we get a timeout
      while(1)
      {
         int bytesRead = socket.Recv(buffer, 10,2000);
         if (bytesRead != 10)
         {
            std::cout << "   Failed to Read" << std::endl;
            std::cout << "   bytesRead = " << bytesRead << std::endl;
            std::cout << "   Errno (" << errno << ") - "
                      << strerror(errno) << std::endl;
            break;
         }

         std::cout << "buffer = " << buffer << std::endl;
         usleep(250000);
      }

      std::cout << "Something went wrong, restart" << std::endl;
   }

   return 0;
}

OUTPUT OF SERVER

./Server 
Wait for Connection
Start to Send Data
Sending Data   byteSent = 10

OUTPUT OF CLIENT

./Client 
Trying to connect to server.
Trying to connect to server.
Connected to Server
   Failed to Read
   bytesRead = 0
   Errno (107) - Transport endpoint is not connected
Something went wrong, restart
Close Socket
Close Socket File Descriptor
Connected to Server
Trying to Recv on a closed socket
Return Value = -1
Errno        = Connection reset by peer

   Failed to Read
   bytesRead = -3
   Errno (104) - Connection reset by peer
Something went wrong, restart
Close Socket
Close Socket File Descriptor
Socket cannot shutdown!
Return Value = -1
Errno        = Transport endpoint is not connected

Trying to connect to server.
Close Socket
Close Socket File Descriptor
Socket cannot shutdown!
Return Value = -1
Errno        = Transport endpoint is not connected
+1  A: 

A return of 0 read bytes from a socket is perfectly legal. This only means you have to wait and try again.

For instance look at this read_data() function. It checks if number of read bytes are > 0, then it stores them. It checks if number of read bytes are < 0, then it is an error.

The 0 case is not really a great success, of course, but not a failure. Just try again. I did not analyze your code in great detail, so there may be something else, but this is an important error often made. (Also, what is in those classes not shown?)

What you could look into is non-blocking sockets. Also see the FAQ for how to tell if a socket is closed on the other end. And maybe consider detecting transfer completion explicitly by sending and end-of-file or marker.

Amigable Clark Kant
Thank you. That was it. I was assuming that 0 meant failure and that the other side actually closed the socket. However, when I modified the code to continue and try again with the read, it works perfectly.
Dennis Miller
This indeed solved my problem, but now I can't figure out if the other side has closed the socket. I thought that receiving a 0 bytes from a read meant that the other side closed the socket. As http://stackoverflow.com/questions/2416944/can-read-function-on-a-connected-socket-return-zero-bytes
Dennis Miller
A return value of 0 from a read usually does mean the socket was disconnected (depending on what socket framework you are using on top of the socket). What you should be doing, especially if using non-blocking sockets, is waiting until the socket reports that is readible before you actually do the reading. In the case of connecting, the socket will report itself as writable when the connection succeeds.
Remy Lebeau - TeamB
@Remy Lebeau, thanks. @Dennis Miller, see my updated post. A select on the socket before you read should tell if it is ready to read.
Amigable Clark Kant