Winsock 1 - TCP Server 
The TCP Server tutorial is the counterpart to the TCP Client tutorial.  These two programs demonstrate how to set up a Client application and communicate with a Server via TCP.  Together, these two apps create a simple connection and can facilitate one-way communication between two hosts.  This tutorial explains the fundamental mechanics involved with a TCP Server.  Subsequent tutorials will assume an understanding of these concepts. 


 


Downloads 
Program Only  TCPServer.exe.  No source files. 
Program and Source Files  TCPServer source files, project files and executable. 
Note:  You must unzip these files with subdirectories!  (example:  "pkunzip -d ws1_full.zip") 


Project Files 


res\client.ico 
res\tcpserver.rc2 
DGModeless.cpp 
DGModeless.h 
resource.h 
stdafx.cpp 
stdafx.h 
TCPServer.aps 
TCPServer.clw 
TCPServer.cpp 
TCPServer.h 
TCPServer.mak 
TCPServer.mdp 
TCPServer.ncb 
TCPServer.rc 
TCPServerDlg.cpp 
TCPServerDlg.h 

All of these files, with the exception of Modeless Dialog files, were generated by App Wizard, using a the dialog-based application template.  Only the files TCPServerDlg.cpp and TCPServerDlg.h were added to for the tutorial code.  One line was added to stdafx.h to enable socket support.  With the exception of the resource files, no other files were changed.  See the section below for discussions on the socket code. 

For details on the Modeless Dialog files, see the discussion on the Modeless Message Box

Discussion 

To understand how this application works, all we need to do is take a detailed look at the file TCPServerDlg.cpp.  This section will also briefly introduce some MFC programming concepts, in case you are unfamiliar with them.  But before we can do anything with sockets, we need to include the Winsock header files into the project.  This is done in stdafx.h

#include <afxsock.h>  // MFC socket extensions 

This is the last line stdafx.h.  It was added manually to allow us to use the Winsock data structures and APIs in our code.  Including this line in stdafx.h lets us use Winsock API's anywhere in our project.  Now, let's take a look at TCPServerDlg.cpp

BEGIN_MESSAGE_MAP(CTCPServerDlg, CDialog) 
    //{{AFX_MSG_MAP(CTCPServerDlg) 
    ON_WM_SYSCOMMAND() 
    ON_WM_PAINT() 
    ON_WM_QUERYDRAGICON() 
    ON_BN_CLICKED(IDC_BN_QUIT, OnBnQuit) 
    ON_BN_CLICKED(IDC_BN_LISTEN, OnBnListen) 
    //}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
This is the Message Map.  This is simply used to associated functions with user-interface events, or "messages."  The line that we care about in the Message Map is: 
    ON_BN_CLICKED(IDC_BN_LISTEN, OnBnListen) 
This line tells us that the function  OnBnListen() will be called when the user hits the "Listen" button.  As it turns out, all the sockets processing happens in this function. 

CTCPServerDlg::CTCPServerDlg(CWnd* pParent /*=NULL*/) 
 : CDialog(CTCPServerDlg::IDD, pParent) 
{ 
    ... 
} 
This is the a standard C++ constructer, no changes are needed. 

CTCPServerDlg::~CTCPServerDlg() 
{ 
    RemoveSockets(); 
} 
This is a standard C++ destructer.  I felt that it was a good place to call our sockets cleanup routine RemoveSockets().  This will be explained more below when socket initialization is discussed. 

void CTCPServerDlg::DoDataExchange(CDataExchange* pDX) 
{ 
    ... 
} 
This function, DoDataExchange(), is where MFC associates C++ class members with their corresponding user interface control.  All of this generated by Class Wizard, so no changes were necessary. 

BOOL CTCPServerDlg::OnInitDialog() 
{ 
    char buf[255]; 
    ... 
//-- Initialization 
    InitSockets_1_1(); 
    m_edLocalName.SetWindowText(GetHostName(buf, 255)); 
    m_edLocalIP.SetWindowText(IPString(uGetLocalIP(), buf, 255)); 
    m_edPort.SetWindowText("4000"); 
  
    return TRUE; 
} 
This function, OnInitDialog(), is called exactly one time, precisely when the dialog starts up.  It is a handy place to do all of our initialization.  We can not do this initialization in the constructer because the constructor is called before some of our members are created and attached to their corresponding user-interface controls.  Most of the code in this function is standard MFC fare. The lines that we are interested in for this tutorial are at the end. 

The first call we make is InitSockets_1_1().  This function determines if the host is capable of supporting Winsock 1.1 functionality.  If it is, this function enables the host to use the Winsock APIs.  Otherwise, the function fails.  If this function succeeds, you must call RemoveSockets() when you are done with the Winsock APIs.  This function is one of our general winsock utility functions.  Refer to Quinn & Shute pp. 320 - 322. 

After InitSockets_1_1(), we simply set up a few of the user-interface controls with some desired values.  The functions GetHostName(), IPString() and uGetLocalIP() are all general winsock utility functions. 

void CTCPServerDlg::OnSysCommand(UINT nID, LPARAM lParam) 
{ 
    ... 
} 

void CTCPServerDlg::OnPaint()  
{ 
    ... 
} 

HCURSOR CTCPServerDlg::OnQueryDragIcon() 
{ 
    ... 
} 
These function are more standard MFC fare.  They were created by App Wizard. 

void CTCPServerDlg::OnBnQuit()  
{ 
    EndDialog(0); 
} 
This function was added manually.  It's sole purpose is to end the application when the user hits the "Quit" button. 

Finally, this function is where the core functionality lies. 
void CTCPServerDlg::OnBnListen()  
 
We need to declare some variables.  We need a client address to fill in, addr_Cli.  Also, because this is a server application, we need to bind the socket to the local host.  For this we need an additional address structure addr_Srv.  We need two sockets, sock_Listen and sock_Acceptsock_Listen is used as the socket that will be listening for the client's message.  Because this is a TCP socket and not a UDP socket, in order to get any data through we need to accept the connection with another socket, so that sock_Listen can continue to be used for listening for clients.  sock_Accept will be the socket we use to accept data from the client.  We also need two string buffers for the message we are receiving and a worksapce for formatting the message, szMessage[256] and buf[255].  We need a port number to listen on, listenport.  We need a temporary string to hold some values for us, csTemp.  And finally, we need an integer to hold the length of the addr_Cli structure, clilen
    SOCKADDR_IN  addr_Srv, addr_Cli;  
    SOCKET       sock_Listen, sock_Accept;  
    char         szMessage[256], buf[255];  
    int          clilen;  
    short        listenport;  
    CString      csTemp;  

Get the port number to listen on and put it in listenport
//-- Get the port to listen on  
    m_edPort.GetWindowText(csTemp);  
    listenport = atoi(csTemp.GetBuffer(0));  
    csTemp.ReleaseBuffer(-1);  
    if (listenport < 1)  
    {  
        AfxMessageBox("Please enter a valid listen port");  
        return;  
    }  

Now, create a TCP socket with the socket() function.  In winsock using TCP/IP, the first and last parameters will always be AF_INET and 0.  The middle parameter determines whether a TCP or UDP socket gets created.  Using SOCK_STREAM will create a TCP socket.  Refer to Quinn & Shute pp. 50 - 53. 
//-- Open a TCP socket to listen on  
    if ((sock_Listen = socket(AF_INET, SOCK_STREAM, 0)) < 0)  
        AfxMessageBox("Unable to create socket");  

Now fill in the local host address structure.  For this purpose, we don't need to know the local host's actual IP address.  We can simply pass the parameter INADDR_ANY and the system will automatically assign an IP address.  Of course, we first need to convert INADDR_ANY to network-byte order with htonl().The function htons() makes sure that the port number is stored in the proper network byte order.  Refer to Quinn & Shute pp. 54 - 55. 
//-- Fill in structure fields for binding to local host  
    memset((char *) &addr_Srv, 0, sizeof(addr_Srv));  
    addr_Srv.sin_family      = AF_INET;  
    addr_Srv.sin_addr.s_addr = htonl(INADDR_ANY);  
    addr_Srv.sin_port        = htons(listenport);  

Now bind the listening socket to the local host.  Refer to Quinn & Shute pp. 57 - 58. 
//-- Bind it  
    if (bind(sock_Listen, (sockaddr*)&addr_Srv, sizeof(addr_Srv)) < 0)  
        AfxMessageBox("Error:  bind() failed.");  

Now put the listening socket in listen mode.  Refer to Quinn & Shute pp. 60 - 61. 
//-- Put the socket in listen mode  
    if (listen(sock_Listen, SOMAXCONN) < 0)  
        AfxMessageBox("Error:  listen() failed.");  

Standard maintenance to prepare the client address structure to recieve new data. 
//-- Prepare Client address to receive new data  
    memset(&addr_Cli, 0, sizeof(addr_Cli));  
    clilen = sizeof(addr_Cli);  

Let the user know that this thread is about to begin a blocking operation. 
//-- Put up a message to let them knowthis thread will be blocking  
    CDGModelessMessage dg("Waiting for TCP message from client...", "Winsock1 - TCP Server");  
    dg.Show();  

Calling accept() will put this thread in blocking mode until it recieves a request for a TCP connection from a client.  When a connection is found, a new socket, sock_Accept, will be created for communication with the client.  Refer to Quinn & Shute pp. 63 - 64. 
//-- Wait for an incoming message (Note:  This blocks!)  
    if ((sock_Accept = accept(sock_Listen, (sockaddr*)&addr_Cli, &clilen)) < 0)  
        AfxMessageBox("Error:  accept() failed.");  

Now recieve the message from the client.  Refer to Quinn & Shute pp. 68 - 69. 
   if (recv(sock_Accept, szMessage, 256, 0) == SOCKET_ERROR)  
    {  
        int res = WSAGetLastError();  
        AfxMessageBox("Error:  recv() failed.");  
    }  
    else  
    {  
If the program got to this point we have recieved a valid message from the client.  It is convenient to pull out the IP address of the client and show it to the user along with the message. 
   //-- We recieved a message.  Show it, along with the source IP address  
        csTemp = "From:  ";  
        csTemp += IPString(uGetIPFromSockAddr_In(&addr_Cli), buf, 255);  
        csTemp += "\n";  
        csTemp += szMessage;  
        AfxMessageBox(csTemp);  
    }  
Now kill the modeless message dialog because our blocking operation is complete. 
    dg.Kill();  
Clean up the two sockets that we have created before we exit. 
    closesocket(sock_Accept);  
    closesocket(sock_Listen);  
 


Back to Winsock 1 Page 
Back to Winsock Tutorials Main Page