Click here to Skip to main content
6,596,602 members and growing! (19,853 online)
Email Password   helpLost your password?
Languages » C / C++ Language » General     Intermediate License: The Code Project Open License (CPOL)

A simple but effective windows socket program

By engulfed111

This windows server socket class wraps winsock functions and gives one the ability to write robust code, without the intricacies of modifing the code.
C++, Windows, Visual Studio, Dev
Posted:22 Jun 2006
Views:36,532
Bookmarked:17 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
9 votes for this article.
Popularity: 2.18 Rating: 2.29 out of 5
2 votes, 22.2%
1
3 votes, 33.3%
2
1 vote, 11.1%
3
2 votes, 22.2%
4
1 vote, 11.1%
5

Introduction

The need to receive commands via the internet from a box running under a unix platform and send responses back to it required that I create a socket server application. I needed a socket class and every tutorial or sample code I found either did not make a robust enough socket class or made the code hard to use(by making it too specific to their use). So I decide to come up with my own code. It allows you to have an over laying code control the socket_server. In a sense that you have an executive class that starts your socket tell it when to send and receive etc.

class server_socket
{
    ///<summary> constructor and destructor</summary>

public:
    //constructs a well known socket structure

    server_socket(int user_port_number);
    //constructs a accepted socket structure

    server_socket();
    //destructor

    ~server_socket();
    ///<summary>Operations</summary>///

public:
    //creates the socket connection

    bool create_socket();
    //accepts a client connection

    bool socket_accept();
    //gives you the socket address

    sockaddr* socket_address();
    //socket send 

    bool socket_send(const char* data_buffer,int data_size);

    //socket receive

    bool socket_receive(char* data_buffer, int data_size);
    //bool socket_receive(char* data_buffer, int data_size);

    //shutdown the socket

    bool socket_shutdown();
protected:
    short port_number; //this is the port number

    struct sockaddr_in socket_structure; //provides the low-level TCP/IP socket structure

    SOCKET    theClient;
};
First of, we pass the port number to listen to as an arguement to the constructor. We then proceed to zero out the socket structure. We assign the Socket address family with its appropriate family in our case this is AF_INET. We have the address which in our case is INADDR_ANY, this tells the server to listen to any type of IP address over the specifed port we assign. And ofcourse we assign the socket port with the port sent as an arguement in the constructor.
server_socket::server_socket(int user_port_number)
:port_number(user_port_number)
{
    memset(&socket_structure, 0, sizeof(struct sockaddr_in));
    socket_structure.sin_family=AF_INET;
    socket_structure.sin_addr.s_addr=INADDR_ANY;
    socket_structure.sin_port=htons(port_number);
    created_from_accept=false;
}
In usual circumstances, you want want your socket code to be able to create a connection (which will deal with the listening and binding to a specific port and ip address ( although it is desirable to have your server socket code listen to any type of IP address coming through a specified port).
bool server_socket::create_socket()
{
    if (created_from_accept)
    {
        return false;
    }//end if (false....

    version=MAKEWORD(2,0); //creates a word which in our case

// is the version of winsock that we are using  winsock2 to be precise

    nret=WSAStartup(version,&wsaData); //this starts up the winsock

    if (nret!=0)
    {
        cout<<"\nCreate_Socket::: Error occured could not create socket\n";
        return false;
    }//end if(nret

    
    listeningSocket=socket(AF_INET,
                           SOCK_STREAM,
                           IPPROTO_TCP);
    if(INVALID_SOCKET==listeningSocket)
    {
        cout<<"\n Create_Socket:::Error: "<<WSAGetLastError()<<" occurred, could not create socket\n";
        WSACleanup();
        return false;
    }//end if(invalid_error.....

    nret=bind(listeningSocket,(LPSOCKADDR)&socket_structure,sizeof(socket_structure));
    if (SOCKET_ERROR==nret)
    {
        cout<<"\n Create_Socket:::Binding Error: "<<WSAGetLastError()<<" occurred, could not create socket\n";
        WSACleanup();
        return false;
    }//end if(socketerror....

    nret=listen(listeningSocket,10); //up to 10 connections may be waiting at any one time to be accepted

    if (SOCKET_ERROR==nret)
    {
        cout<<"\n Create_Socket:::Listening Error: "<<WSAGetLastError()<<" occurred, could not create socket\n";
        WSACleanup();
        return false;
    }//end if (socket_error.....

        cout<<"socket created\n";
    return true;
}
Looking at the code the first thing we do is determine what version of winsock we plan to use and then startup winsock with the WSAStartup call. It is key to ensure that the startup call works as no futher winsock action should be taken if it is unsuccessful. The next thing we do is create the listening socket using the socket function. The socket operation takes in the address family specification, the type of socket (in our case is a socket stream) and finally the protocol as arguements. Once the socket is created, you bind it to the specified address which we specified in the constructor. We are now ready to listen for a connection.In the code I am able to listen to a maximum of 10 connections at a time. But the key thing to notice is that since I am utilizing a sychronous socket implementation we can only accept one connection at a time. The listening will hold all 10 connections, but the accept function will accept one connection at a time. Once we hear an incoming connection we call the accept function do its thing.
int socket_struct_size=sizeof(socket_structure);
    theClient=accept(listeningSocket,
                     NULL, //new_socket->socket_address(),

                     NULL);//&socket_struct_size);

    if(INVALID_SOCKET==theClient)
    {
        cout<<"\n Accept_Socket:::Listening Error: "<<WSAGetLastError()<<" occurred, could not create socket\n";
        WSACleanup();
        return false;
    }//end if(INVALID_SOCKET....


    //listeningSocket=theClient;  //this is wrong when you do 

//this you servere the connection after your first disconnect

    cout<<"socket_accepted\n";
    return true;
The accept function accept the connection and returns the descriptor to the new connection. I called this (theClient), this is what enables us read and write to connected client. The commented out listeningSocket = theClient was left there just to ensure that people do not make the same mistake I made when I wrote this class. While looking through MSDN the equated the lsitening socket with the value of the equated accepted descriptor. The reason they did this was because all they wanted was one connection and end the application. In our situation we dont to leave the control of that to the server socket class.
bool server_socket::socket_send(const char *data_buffer, int data_size)
{
    int number_of_bytes_transferred=0;
    bool return_value=true;
    number_of_bytes_transferred=send(theClient,
                                     data_buffer,
                                     data_size,
                                     0);
    if (SOCKET_ERROR==number_of_bytes_transferred)
    {
        return_value=false;
    }
    else
    {
        if(number_of_bytes_transferred==data_size)
        {
            return_value=true;
        }
        else
        {
            return_value=false;
        }//end if (number_of_bytes_ transferred

    }//end if(socket_error....

    return true;
}
Once we have accepted a connection we can either send or receive. The code above shows you how to send data. The send command takes in the accepted connection descriptor, the data to transfered and the size of the data to be tranferred as arguements and returns the number of bytes tranferred.
bool server_socket::socket_receive(char* data_buffer,int data_size)
{
    bool return_value=true;
    int socket_return_value;
    int total_received=0;
    while((return_value !=0)&&(total_received<data_size))
    {
        socket_return_value=recv(theClient,
                                 (data_buffer)+total_received,  //const_cast<char*>

                                 (data_size-total_received),
                                 0);
        if((socket_return_value<=0)||(socket_return_value==WSAECONNRESET))
        {
            return_value = false;
            break;
        }
        else
        {
            total_received=total_received+socket_return_value;
        }//end if((socket_return_value.....

        
    }//end while((return_value......

    if(data_size==total_received)
        {
            return_value=true;
        }
        else
        {
            return_value=false;
        }
    return return_value;
The receive is just like the send, the difference is we enclose the receive command in a while loop to ensure that we receive everything sent to us. in my implementation I have a fixed header that I receive that tells me the size of what else is coming to me. Hence my checking to make sure that the total received is equal to the datasize sent in as an arguement.
bool server_socket::socket_shutdown()
{
    closesocket(theClient);
    
    return true;
}
Once we are done with the accepted connection we close the socket using the closesocket function. We are still able to listen for connections because the listening socket is still alive.
server_socket::~server_socket()
{
    closesocket(listeningSocket);
    WSACleanup();
}
Finally once we are done listening, we close the listening socket and we are done. This is but a simple implementation of using winsock. And for what I needed it to do, it did. As an example of how to use the socket server example. I create a function that deals with setting up the socket_ server and another function that deal with the sending and receiving.
void run_server()
{
    server_socket* the_Server_socket;
    bool continue_flag = true;
    the_Server_server = new server_socket(port_number);
    if (the_Server_socket->create_socket() == false)
    {
        cout<<"executive::run():  ERROR:  Call to create_socket failed.  Constructor failed.\n"<<flush;
        return false;
    }
    // Accept new connect requests and spawn threads to process them

    while (continue_flag)
    {
        if (the_Server_socket->socket_accept() == false)
        {
            cout<<"executive::run():  ERROR:  Accept error occurred.\n"<<flush;
	
            //return false;

        }
        else
        {
            num_clients_so_far++;
			cout << "Accepted new connection:  client " << dec << num_clients_so_far <<"\n" << flush;    
            // Receive and process and commands. 

           	receive_loop(the_Server_socket);
        }
    } // while (true)                

	itsServer_socket->socket_shutdown();

}

receive_loop(server_socket *new_Server)
{
   bool return_status =true;
   char input_buffer [10];
  while ( (return_status = new_Server->socket_receive( input_buffer, 10)!=false)) 
  {
      //put your code here to deal with the received data

  }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

engulfed111


Member

Occupation: Engineer
Location: United States United States

Other popular C / C++ Language articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 2 of 2 (Total in Forum: 2) (Refresh)FirstPrevNext
QuestionHelp PinmemberRobocop1313139:58 8 Jun '09  
AnswerRe: Help Pinmemberengulfed11116:20 28 Jul '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 22 Jun 2006
Editor:
Copyright 2006 by engulfed111
Everything else Copyright © CodeProject, 1999-2009
Web09 | Advertise on the Code Project