Link to home
Start Free TrialLog in
Avatar of wonjun
wonjun

asked on

Networking

This question is for an expert who knows WINSOCK programming.

I have these four files, this is from the book MULTILPLAYRE GAME PROGRAMMING, so if this content isn't appropriate to be here, please delete my questions.

I compiled these files in Visual Studio.net 2005 ( you need ws2_32.lib included in project), then I opened cmd.exe,

and ran one,

connectiontest server 6000

opened another cmd.exe and ran,

connectiontest client 243.54.56.76(my ip address) 6000

THEN,

on the client side, the data, "TestData from client" is sent successfully,
but on the server side, the byte received is -1.

I used WSAGetLastError() function to see what was the error, and i get WSAECONNRESET 10054 in return.

I spent hours trying to debug, but i just cannot figure. Could anyone grab these source code and run them and tell me why this isn't working?

Thank you very much.

/////////////////////////////ConnectionTest.h/////////////////////////////////////////////////////////////
#include <iostream>

#include "SocketObject.h"

using namespace std;

void vServerConnection(int iListenPort);
void vClientConnection(char *szServerIP, int iServerListenPort);

void PrintHelp();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////ConnectionTest.cpp/////////////////////////////////////////////////////////////
#include "ConnectionTest.h"

int main(int argc, char *argv[])
{
      if(argc == 3 && strcmp(argv[1], "server") == 0)
      {
            //if user selected server, listen on the given port
            //and assign connection to the second port number
            vServerConnection( atoi(argv[2]));
      }
      else if(argc == 4 && strcmp(argv[1], "client") == 0)
      {
            //user selected client: connect to given port and IP address
            vClientConnection(argv[2], atoi(argv[3]) );
      }
      else
      {
            PrintHelp();
            return 0;
      }

      return 1;
}

void vServerConnection(int iListenPort)
{
      SocketObject ServerSocketObject;
      SocketObject ClientSocketObject;
      char             DataPacket[128];            //Data packet to receive
      int                   iBytesReceived = 0;    //# of Bytes received

      cout<<"<Server> Attemption to listen on Port" << iListenPort <<endl;

      //Attempt to start the server on port 6000
      if(ServerSocketObject.Bind(iListenPort))
      {
            cout<<"<Server> Listening" <<endl;

            //Listen for conneciton on the listen port
            ServerSocketObject.Listen();

            //Accept the connection
            ServerSocketObject.Accept(ClientSocketObject);

            cout<<"<Server> Client Connected to Port" << iListenPort <<endl;

            //receive data
            iBytesReceived = ClientSocketObject.Recv(DataPacket, 128, 0);
            cout << "<Server> Received " << iBytesReceived << "Bytes" << endl;
            cout << "<Server> Data Received = " << DataPacket << endl;

            //Disconnect the client
            ClientSocketObject.Disconnect();

            cout<<"<Server> Client Disconnected" <<endl;
      }
      else
      {
            cout<<"<Server> Failed to listen" << endl;
      }
}

void vClientConnection(char *szServerIP, int iServerListenPort)
{
      SocketObject ClientSocketObject;
      char             DataPacket[128];      //Data Packet to transmit
      int                   iBytesSent = 0;      //# of bytes sent

      cout<<"<Client> connecting to " << szServerIP <<", Port" << iServerListenPort <<endl;

      //Connect to the IP and Port
      if(ClientSocketObject.Connect(szServerIP, iServerListenPort))
      {
            cout << "<Client> Connected" <<endl;

            //populate the data packet
            strcpy_s(DataPacket, "TestData from client");

            //Send Data
            iBytesSent = ClientSocketObject.  Send(DataPacket, 128, 0);

            cout << "<Server> Data Transmitted = " << DataPacket << endl;
            cout << "<Client> Transmitted " << iBytesSent << "Bytes" << endl;


            //Disconnect from the server
            ClientSocketObject.Disconnect();

            cout<<"<Client> Disconnected from Server" <<endl;
      }
      else
      {
            cout << "<Client> Failed to connect" <<endl;
      }
}

void PrintHelp()
{
      cout << "-------------------------------------------------" << endl;
      cout << "              ConnectionTest Help                " << endl;
      cout << "-------------------------------------------------" << endl;
      cout << "Usage: ConnectionTest [client/server] [ip, port/port, port]" << endl;
      cout << "" << endl;
      cout << "Example: ConnectionTest client 198.168.0.1 6000" << endl;
      cout << "" << endl;
      cout << "Example: ConnectionTest server 6000" << endl;
      cout << "" << endl;
}
//////////////////////////////////SocketObject.h//////////////////////////////////////////////////
//###################################################################################
//#                                                                                                                              #
//#                  Chapter 7 - Socket Object Class Definition                                                #            
//#                                                                                                                              #
//#                                    Class to Handle Client/Server Communication                              #
//#                                                                                                                              #
//#                                    Todd Barron, 08/06/2000                                                            #
//#                                                                                                                              #
//###################################################################################

#ifndef SOCKET_OBJECT

#define SOCKET_OBJECT

// Windows Sockets Include, Also need ws2_32.lib included in project
#include <winsock2.h>
#include <iostream>

using namespace std;

struct stPacketHeader
{
      int            iType;
      int            iLength;
      int            iID;
      int            iCheckSum;
      int            iSender;
};

struct SocketTransmissionStruct
{
      SOCKET            skSocket;
      char            szBuffer[64000];
      int                  iWritePos;
      int                  iReadPos;
      int                  iTerminate;
};

// Class Object
class SocketObject  
{
      private:

      public:
            SOCKET                                    skSocket;
            int                                          iStatus;
            SocketTransmissionStruct      stReceive;      
            SocketTransmissionStruct      stSend;      
            DWORD                                    dwReceiveHandle;
            DWORD                                    dwSendHandle;

            // Constructor
            SocketObject();
            // Desctrucot
            ~SocketObject();

            // Accept a client's request to connect
            bool Accept(SocketObject& skAcceptSocket);
            // Listen for clients to connect
            int Listen( void );
            // Open a server listening port
            int Bind(int iPort);
            // Close connection
            void Disconnect();
            // Connect to a server
            bool Connect(char* szServerAddress, int iPort);

            int Recv(char *szBuffer, int iBufLen, int iFlags);
            int Send(char *szBuffer, int iBufLen, int iFlags);

            // Misc Functions
            int iCalculateChecksum(stPacketHeader stHead);

            // Asynchronous Functions
            static void thrReceiveThread(SocketTransmissionStruct *rs);
            static void thrSendThread(SocketTransmissionStruct &rs);
            int vGetPacket(char *szbuffer);
};

#endif


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////SocketObject.cpp/////////////////////////////////////////////////////////////////
//###################################################################################
//#                                                                                                                              #
//#                                    Socket Object Member Functions                                                #            
//#                                                                                                                              #
//#                                    Class to Handle Client/Server Communication                              #
//#                                                                                                                              #
//#                                    Todd Barron, 08/06/2000                                                            #
//#                                                                                                                              #
//###################################################################################

#include "SocketObject.h"

// Constructor
SocketObject::SocketObject()
{
      WSADATA wsaData;
      WORD      wVersionRequested;

      wVersionRequested = MAKEWORD( 2, 0 );

      skSocket = INVALID_SOCKET;
      iStatus = WSAStartup(wVersionRequested,&wsaData);
}

// Destructor
SocketObject::~SocketObject()
{
      CloseHandle(&dwReceiveHandle);
      Disconnect();
}

int SocketObject::vGetPacket(char *szbuffer)
{
      int                        iBytesReceived = 0;
      int                        iBytesWaiting = 0;
      stPacketHeader      stHeader;

      // Check if write pos moved
      if( stReceive.iWritePos != stReceive.iReadPos ) {
            //
            // Pull packet header from buffer
            //
            iBytesWaiting = (stReceive.iWritePos - stReceive.iReadPos);
            // Make sure a full size header is present
            if( iBytesWaiting < sizeof(stHeader) ) {
                  return(0);
            }
            // Copy the header in
            memcpy(&stHeader,&stReceive.szBuffer[stReceive.iReadPos],sizeof(stHeader));
            // Check the checksum
            if( ((stHeader.iType+stHeader.iLength+stHeader.iID)) != stHeader.iCheckSum ) {
                  // Skip the first bad byte in an attempt to find a good packet
                  stReceive.iReadPos++;
                  if( stReceive.iReadPos >= 64000 ) {
                        stReceive.iReadPos = 0;
                  }
                  // Try again for a good packet
                  vGetPacket(szbuffer);
            }
            else {
            }

            //
            // Pull the body of the packet according to the size
            //
            
            // Make sure enough data is waiting, if not leave and try again later
            if( (iBytesWaiting-sizeof(stHeader)) < (unsigned)stHeader.iLength ) {
                  return(0);
            }
            // Copy into the return buffer
            memcpy(szbuffer,&stHeader,sizeof(stHeader));
            memcpy(&szbuffer[sizeof(stHeader)],&stReceive.szBuffer[stReceive.iReadPos+sizeof(stHeader)],stHeader.iLength);

            // Update Read Position & Return Values
            stReceive.iReadPos += (stHeader.iLength+sizeof(stHeader));
            iBytesReceived = (stHeader.iLength+sizeof(stHeader));
            
            // Check if reading too far
            if( stReceive.iReadPos >= 64000 ) {
                  stReceive.iReadPos = 0;
            }
      }

      return(iBytesReceived);
}

void SocketObject::thrReceiveThread(SocketTransmissionStruct *rs)
{
      int                        iBytesReceived;
      char                  *szTempBuffer;
      int                        iBytesPart1;
      int                        iBytesPart2;

      szTempBuffer = new char[32768];

      // Receive data until given notice to terminate
      while( rs->iTerminate != 1 ) {
            // Read from the pipe
            iBytesReceived = recv( rs->skSocket, szTempBuffer, 32768, 0 );
            if( iBytesReceived > 0 ) {
                  // Make sure the packet does not overrun the write buffer
                  if( (rs->iWritePos+iBytesReceived) >= 64000 ) {
                        iBytesPart1 = ((rs->iWritePos+iBytesReceived)-64000);
                        iBytesPart2 = (64000 - rs->iWritePos);
                        memcpy( &rs->szBuffer[rs->iWritePos], szTempBuffer, iBytesPart1 );
                        memcpy( &rs->szBuffer[0], &szTempBuffer[iBytesPart1], iBytesPart2 );
                        rs->iWritePos = iBytesPart2;
                  }
                  else {
                        // Write to the permanent buffer
                        memcpy( &rs->szBuffer[rs->iWritePos], szTempBuffer, iBytesReceived );
                        rs->iWritePos += iBytesReceived;
                  }
            }
      }

      delete [] szTempBuffer;
}

void SocketObject::thrSendThread(SocketTransmissionStruct &rs)
{
      int iBytesSent;
      
      iBytesSent = send( rs.skSocket, rs.szBuffer, 128, 0 );
}

// Connect
bool SocketObject::Connect(char* szServerAddress, int iPort)
{
      struct            sockaddr_in serv_addr;
      LPHOSTENT      lphost;

      memset(&serv_addr,0,sizeof(sockaddr_in));
      serv_addr.sin_family = AF_INET;
      serv_addr.sin_addr.s_addr = inet_addr(szServerAddress);

      if (serv_addr.sin_addr.s_addr == INADDR_NONE)
      {
            lphost = gethostbyname(szServerAddress);
            if (lphost != NULL)
                  serv_addr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
            else
            {
                  WSASetLastError(WSAEINVAL);
                  return FALSE;
            }
      }

      serv_addr.sin_port = htons(iPort);

      // Open the socket
      skSocket = socket(AF_INET, SOCK_STREAM, 0);
      if(skSocket == INVALID_SOCKET)
      {
            return false;
      }

      int err = connect(skSocket, (struct sockaddr*)&serv_addr,sizeof(sockaddr));
      if(err == SOCKET_ERROR)
      {
            Disconnect();
            return false;
      }

      
      stReceive.skSocket = skSocket;
      stReceive.szBuffer[0] = NULL;
      stReceive.iReadPos = 0;
      stReceive.iWritePos = 0;
      stReceive.iTerminate = 0;

      // Create the thread to receive data
      CreateThread(
            NULL,  // pointer to security attributes
            NULL,                         // initial thread stack size
            (LPTHREAD_START_ROUTINE ) &thrReceiveThread,     // pointer to thread function
            &stReceive,                        // argument for new thread
            NULL,                     // creation flags
            &dwReceiveHandle          // pointer to receive thread ID
      );

      return true;
}

void SocketObject::Disconnect()
{
      if(skSocket != INVALID_SOCKET)
      {
            closesocket(skSocket);
            skSocket = INVALID_SOCKET;
      }
}

int SocketObject::Bind(int iPort)
{
      sockaddr_in saServerAddress;

      skSocket = socket(AF_INET, SOCK_STREAM, 0);
      
      if(skSocket == INVALID_SOCKET)
      {
            return false;
      }

      memset(&saServerAddress, 0, sizeof(sockaddr_in));

      saServerAddress.sin_family = AF_INET;
      saServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);
      saServerAddress.sin_port = htons(iPort);

      if( bind(skSocket, (sockaddr*) &saServerAddress, sizeof(sockaddr)) == SOCKET_ERROR)
      {
            Disconnect();
            return false;
      }
      else
            return true;
}

int SocketObject::Listen( void )
{
      return listen( skSocket, 32 );
}

bool SocketObject::Accept( SocketObject &skAcceptSocket )
{
      sockaddr_in saClientAddress;
      int                  iClientSize = sizeof(sockaddr_in);
      SOCKADDR      IPAddress;

      skAcceptSocket.skSocket = accept( skSocket, (struct sockaddr*)&saClientAddress, &iClientSize );
      
      if( skAcceptSocket.skSocket == INVALID_SOCKET )
      {
            return false;
      }
      else
      {
            memcpy(&IPAddress,&saClientAddress,sizeof(saClientAddress));
            printf("%d.%d.%d.%d is Connecting\n",saClientAddress.sin_addr.S_un.S_un_b.s_b1,saClientAddress.sin_addr.S_un.S_un_b.s_b2,saClientAddress.sin_addr.S_un.S_un_b.s_b3,saClientAddress.sin_addr.S_un.S_un_b.s_b4);

            skAcceptSocket.stReceive.skSocket = skAcceptSocket.skSocket;
            skAcceptSocket.stReceive.szBuffer[0] = NULL;
            skAcceptSocket.stReceive.iReadPos = 0;
            skAcceptSocket.stReceive.iWritePos = 0;
            skAcceptSocket.stReceive.iTerminate = 0;
            
            // Create the thread to receive data
            CreateThread(
                  NULL,                                                                                          // pointer to security attributes
                  NULL,                                                                                          // initial thread stack size
                  (LPTHREAD_START_ROUTINE ) &skAcceptSocket.thrReceiveThread,     // pointer to thread function
                  &skAcceptSocket.stReceive,              // argument for new thread
                  NULL,                                                      // creation flags
                  &skAcceptSocket.dwReceiveHandle         // pointer to receive thread ID
            );

            return true;
      }
}

int SocketObject::Recv( char *szBuffer, int iBufLen, int iFlags)
{
      return recv(skSocket, szBuffer, iBufLen, iFlags);
}

int SocketObject::Send(char *szBuffer, int iBufLen, int iFlags)
{
      return send(skSocket,szBuffer,iBufLen,iFlags);
}

int SocketObject::iCalculateChecksum(stPacketHeader stHead)
{
      int      iChecksum = 0;

      iChecksum = (stHead.iID+stHead.iLength+stHead.iType);

      return(iChecksum);
}




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ASKER CERTIFIED SOLUTION
Avatar of rajeev_devin
rajeev_devin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of rajeev_devin
rajeev_devin

Also you are reading data in main thread through this function
 iBytesReceived = ClientSocketObject.Recv(DataPacket, 128, 0);
You didn't even have taken any mutex for synchronization.
Avatar of wonjun

ASKER

so how should i change the code to make it work? i'm quite lost.
Thank you.
Avatar of wonjun

ASKER

OHHH i get it thank you ver ymuch,....those receive thread outside of main aren't supposed to be there, but the bookis so poorly organized and i didn even notice it got in there!!!

thank you for pointing that out. that was exactly what i forgot to look for..
My pleasure :)