[Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

c++ socket server - WSAEISCONN 10056 error

Posted on 2012-09-04
3
Medium Priority
?
1,157 Views
Last Modified: 2012-09-05
Hi,

I have created an app that communicates via tcp sockets. The socket isn't asynchronous (This suits my needs) and I'm receiving the error when trying to invoke listen() on the server after one successful call.

can anybody see why this is occurring?

socket.h:
#pragma once //Only process header files once
#pragma comment(lib, "WS2_32.lib") //Add "WS2_32.lib" as a linker input
#include <iostream> //Input/output stream
#include "WinSock2.h" //Include WinSock
 
using namespace std; //Standard namespace
 
const int STRLEN = 1024; //Max length of our messages
 
class Socket //Socket base class
{
    protected:
        WSADATA wsaData; //wsaData
        SOCKET mySocket; //Socket
        SOCKET myBackup; //Socket
        SOCKET acceptSocket; //Socket
        sockaddr_in myAddress; //Socket Address
    public:
        Socket(); //"Prototype" constructor<
        ~Socket(); //"Prototype" destructor
        bool SendData( char* ); //"Prototype" SendData
        bool RecvData( char*, int ); //"Prototype" RecvData
        void CloseConnection(); //"Prototype" CloseConnection
        void GetAndSendMessage(); //"Prototype" GetAndSendMessage
}; //End base class
 
class ServerSocket : public Socket //Create our server socket class (derived)
{
    public:
        void Listen(); //"Prototype" Listen
        void Bind( int port ); //"Prototype" Bind
        void StartHosting( int port ); //"Prototype" StartHosting
}; //End ServerSocket class
 
class ClientSocket : public Socket //Create our client socket class (derived)
{
    public:
        void ConnectToServer( const char *ipAddress, int port ); //"Prototype" ConnectToServer
};

Open in new window


Socket impl:
#include "stdafx.h"
#include "Socket.h"
 
Socket::Socket() //Constructor
{
    if( WSAStartup( MAKEWORD(2, 2), &wsaData ) != NO_ERROR ) //WsaStartup
    {
        cerr<<"Socket Initialization: Error with WSAStartup\n"+WSAGetLastError(); //Error
        system("pause"); //Pause the program
        WSACleanup(); //Clean up
        exit(10); //Exit
    }
 
    //Create a socket
    mySocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); //Set our socket variable
 
    if ( mySocket == INVALID_SOCKET ) //If the socket didn't set correctly
    {
        cerr<<"Socket Initialization: Error creating socket"+WSAGetLastError()<<endl; //Error
        system("pause"); //Pause the program
        WSACleanup(); //Clean up
        exit(11); //Exit
    }
 
    myBackup = mySocket; //Set the backup socket to the socket
}
 
Socket::~Socket() //Destructor
{
    WSACleanup(); //Clean up
}
 
bool Socket::SendData( char *buffer ) //SendData
{
    send( mySocket, buffer, strlen( buffer ), 0 ); //Send the data
    return true; //Return true
}
 
bool Socket::RecvData( char *buffer, int size ) //RecvData
{
    int i = recv( mySocket, buffer, size, 0 );
    buffer[i] = '\0';
    return true;
}
 
void Socket::CloseConnection()
{
    //cout<<"==CLOSE CONNECTION=="<<endl;
    closesocket( mySocket ); //Close the socket
    mySocket = myBackup; //Set the socket to the backup
}
 
void Socket::GetAndSendMessage() //GetAndSendMessage
{
    char message[STRLEN];//Char array
    cin.ignore();//Without this it uses the return char from last cin and passes this one!
    cout<<"> ";
    cin.get( message, STRLEN ); //Get the message
    SendData( message ); //Send the data
}
 
void ServerSocket::StartHosting( int port ) //StartHosting (for our ServerSocket class)
{
     Bind( port ); //Bind to the port
     Listen(); //Listen for connection attempts
}
 
void ServerSocket::Listen() //Listen (for our ServerSocket class)
{
    //cout<<"LISTEN FOR CLIENT..."<<endl;
 
    if ( listen ( mySocket, 1 ) == SOCKET_ERROR ) //If there is a problem
    {
		 int i = WSAGetLastError();
        cerr<<"ServerSocket: Error listening on socket\n"+WSAGetLastError(); //Error
        system("pause"); //Pause the program
        WSACleanup(); //Clean up
        exit(15); //Exit
    }
 
    //cout<<"==ACCEPT CONNECTION=="<<endl;
 
    acceptSocket = accept( myBackup, NULL, NULL ); //Attempt to accept connection
    while ( acceptSocket == SOCKET_ERROR ) //While there is a problem
    {
        acceptSocket = accept( myBackup, NULL, NULL ); //Try to accept
    }
    mySocket = acceptSocket; //Set mySocket to acceptSocket
}
 
void ServerSocket::Bind( int port ) //Bind (for our ServerSocket class)
{
    myAddress.sin_family = AF_INET; //sin_family is always supposed to be AF_INET
    myAddress.sin_addr.s_addr = inet_addr( "0.0.0.0" ); //IP it connects to (dont need for server)
    myAddress.sin_port = htons( port ); //The port
 
    //cout<<"==BIND TO PORT=="<<port<<endl;
 
    if ( bind ( mySocket, (SOCKADDR*) &myAddress, sizeof( myAddress) ) == SOCKET_ERROR ) //If there is a problem
    {
        cerr<<"ServerSocket: Failed to connect\n"+WSAGetLastError(); //Error
        system("pause"); //Pause the program
        WSACleanup(); //Clean up
        exit(14); //Exit
    }
}
 
void ClientSocket::ConnectToServer( const char *ipAddress, int port ) //ConnectToServer (for our ClientSocket class)
{
    myAddress.sin_family = AF_INET; //sin_family is always supposed to be AF_INET
    myAddress.sin_addr.s_addr = inet_addr( ipAddress ); //IP it connects to
    myAddress.sin_port = htons( port ); //The port
 
    //cout<<"==CONNECTED=="<<endl;
 
    if ( connect( mySocket, (SOCKADDR*) &myAddress, sizeof( myAddress ) ) == SOCKET_ERROR ) //If there is a problem
    {
        cerr<<"ClientSocket: Failed to connect\n"+WSAGetLastError(); //Error
        system("pause"); //Pause the program
        WSACleanup(); //Clean up
        exit(13); //Exit
    }
}

Open in new window


SocketServer class
#include "stdafx.h"
#include "SocketServer.h"
#include <vector>
#include <iterator>

bool NFLSocketServer::run()
{
	cout<<"==HOSTING=="<<endl; //Tell the user we are hosting
    //sockServer.StartHosting( port ); //StartHosting

	sockServer.Bind(this->port);

	this->done = false;
	//Connected
	bool connected = false;


	while ( !done )
	{
		cout << "Listening for connections..." << endl;

		sockServer.Listen();

		connected = true;

		while(connected)
		{
			//initialise buffer
			//vector<string> buffer;
			string accum;
			bool filling = true;
			//fill the buffer
			while(filling)
			{
				cout << "-------- READ ---------" << endl;
				//read off socket
				sockServer.RecvData( recMessage, STRLEN ); //Receive data
       
				string msg(recMessage);
				cout << msg << endl;
				Message::trim(msg);
				accum += msg + " ";


				if(accum.size() > 0 && accum.find(" end ")!= string::npos )
				{
					filling = false;
				}
			}


			vector<string> buffer = Message::split(accum);
			
			
			if(buffer.size() > 0 )
			{
				//buffer.back().compare("end")==0
				int backIndex = buffer.size()-1;
				while(buffer[backIndex].compare("")==0 && backIndex >=0)
				{
					backIndex--;
				}

				if(buffer[backIndex].compare("end")==0)
				{
					cout << "Buffer filled" << endl;
					this->process(buffer);
				}
				else 
				{
					cout << "invalid buffer. " << endl;
				}
			}
			else 
			{
				cout << "invalid buffer. " << endl;
			}
		
			connected = false;
		}
	}
	return done;
}

bool NFLSocketServer::process(vector<string> data)
{
	//internal logic, i dont think this affects server execution

	return success;
}

void NFLSocketServer::setIPAddress(string ip)
{
	this->ipAddress = ip;
}

void NFLSocketServer::setPort(int portNum)
{
	this->port = portNum;
}


}

Open in new window



An exception is thrown on this line: sockServer.Listen(); after one call has been processed.

Any help appreciated
0
Comment
Question by:basil365
3 Comments
 
LVL 36

Accepted Solution

by:
mccarl earned 1000 total points
ID: 38366189
The problem would be because you are calling listen() on the socket that is already listening. The listen() call should only be made once, it is the accept() call that is made after the server has served each client. General outline in pseudocode is...


listen(serverSocket);

while(true) {
   socket = accept(serverSocket);

   recv(socket, ...);
   send(socket, ...);
   send(socket, ...);
   // etc, etc

   close(socket);
}

Also, note that there are two distinct sockets in the above. The 'serverSocket' that represents the socket that is listening for connections from clients, and there is only one of these and it stays the same for the whole duration while your server is running. Then there is the 'socket' which represents just the individual connection to a particular client. There ends up being many of these, one for each client connection that has come in to your server. In your code, while it may eventually work, you might also want to change things around to make this distinction, rather than what you have now with mySocket, myBackup, acceptSocket, etc.
0
 
LVL 9

Assisted Solution

by:Orcbighter
Orcbighter earned 1000 total points
ID: 38367563
I have spotted  a few problems here:
1. Only call WSACleanup if you have previously successfully called WSAStartup, not after failing a call to WSAStartup. The easiest way to do this is to add a boolean member variable to your Socket class (say m_bInitialised). If you successfully call WSAStartup then set it to true.
Then in your destructor test if the boolean is true before calling WSACleanup.
NOTE: be sure to close the socket first in the destructor before calling WSACleanup.

2: You should initialise your Socket member variables in the Socket constructor before using them, eg:
Class Socket
  : mySocket( NULL ),
    myBackup( NULL ),
    acceptSocket( NULL ),
    m_bInitialised( false )
{
    SecureZeroMemory( &myAddress, sizeof( sockaddr_in ));
    SecureZeroMemory( &wsaData, sizeof( WSADATA ));

    ...
}

3: Unless you want to use exceptions, I would not initialise and create the socket in the class constructor.
If something fails in the constructor you have no way of knowing what really broke.
I would create a public method (called for example, Initialise() or Enable() returning a boolean.
In this way, you can capture any errors much easier, eg:

bool Socket::Initialise()
{
    bool retStatus = true;
   
    // call WSAStartup, set status to false on error
   
    // if OK, create socket, return false on error
    // do any other initialising stuff
    return retStatus;
}

in your server class

...
   bool bCallStatus = true;
  Socket sockServer;
 
  if ( !sockServer.Initialise() )
  {
    // handle error
  }
  else
  {
       bCallStatus = sockServer.Bind( this->port );   // modify this to return a status
       // any errors and cleanup will be handled by the Socket destructor, no need to keep erroneously calling WSACleanup
       ... etc
  }

  4.  mccarl is correct about the listen call.
  You should remove the accept(..) call from the Listen method of the Socket class (which should only be called once at the beginning of your program, after initialising the socket class) and place it in its own method.
  In fact, you could create a static method in the SocketServer class and pass it as a thread process into its own thread, and use the this pointer of the SocketServer class as a thread parameter. This static method could then call the Socket::OnAccept() method, in which the accept call is made. In this way your server class could handle many client threads.
0
 

Author Closing Comment

by:basil365
ID: 38367626
Thanks for your help guys - i'll follow your points and clean it up a bit.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
Suggested Courses

865 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question