Click here to Skip to main content
Email Password   helpLost your password?

Screenshots

Note: The demo can be started in Client or Server mode, executed with "/C" (or "/CLIENT") or "/S" (or "/SERVER", which is the default).

Server Socket App - Screenshot

Client Socket App - Screenshot

Introduction

This article is about a client/server multi-threaded socket class. The thread is optional since the developer/designer is still responsible for deciding if he/she needs it. There are other Socket classes here and other places over the Internet, but none of them can provide feedback (event detection) to your application like this one does. It provides you with the following events detection: connection established, connection dropped, connection failed and data reception (including 0 byte packet).

Description

This article presents a new socket class which supports both TCP and UDP communication. It provides some advantages compared to other classes that you may find here or on some other Socket Programming articles. First of all, this class doesn't have any limitation like the need to provide a window handle to be used. This limitation is bad if all you want is a simple console application. So, this library doesn't have such a limitation. It also provides threading support automatically for you, which handles the socket connection and disconnection to a peer. It also features some options not yet found in any socket classes that I have seen so far. It supports both client and server sockets. A server socket can be referred as to a socket that can accept many connections. A client socket is a socket that is connected to a server socket. You may still use this class to communicate between two applications without establishing a connection. In the latter case, you will want to create two UDP server sockets (one for each application). This class also helps reduce coding needed to create chat-like applications and IPC (Inter-Process Communication) between two or more applications (processes). Reliable communication between two peers is also supported with TCP/IP with error handling. You may want to use the smart addressing operation to control the destination of the data being transmitted (UDP only). TCP operation of this class deals only with communication between two peers.

Now for those not familiar with IP Socket, the following section will give some details on how it works. This is also the goal with this article: to explain the basic functionality behind socket objects.

TCP/IP Stack

The TCP/IP stack is shorter than the OSI one:

TCP is a connection-oriented protocol, while UDP (User Datagram Protocol) is a connectionless protocol.

IP Datagrams

The IP layer provides a connectionless and unreliable delivery system. It considers each datagram independently of the others. Any association between datagrams must be supplied by the higher layers. The IP layer supplies a checksum that includes its own header. The header includes the source and destination addresses. The IP layer handles routing through the Internet. It is also responsible for breaking up large datagrams into smaller ones for transmission and reassembling them at the other end.

UDP

UDP is also connectionless and unreliable. What it adds to IP is a checksum for the contents of the datagram and port numbers. These are used to give a client/server model: see later.

TCP

TCP supplies logic to give a reliable connection-oriented protocol above IP. It provides a virtual circuit that two processes can use to communicate.

Internet Addresses

In order to use a service, you must be able to find it. The Internet uses an address scheme for machines so that they can be located. The address is a 32-bit integer which gives the IP address. This encodes a network ID and more addressing. The network ID falls into various classes according to the size of the network address.

Network Address

Class A uses 8 bits for the network address with 24 bits left over for other addressing. Class B uses 16-bit network addressing; class C uses 24-bit network addressing and class D uses all 32.

Subnet Address

Internally, the Unix network is divided into subnetworks. Building 11 is currently on one subnetwork and uses 10-bit addressing, allowing 1024 different hosts.

Host Address

8 bits are finally used for host addresses within our subnet. This places a limit of 256 machines that can be on the subnet.

Total Address

The 32-bit address is usually written as 4 integers separated by dots.

Port Addresses

A service exists on a host and is identified by its port. This is a 16-bit number. To send a message to a server, you send it to the port for that service of the host that it is running on. This is not location transparency! Some of these ports are "well known." For example:

tcpmux 1 TCP
echo 7 UDP
echo 7 TCP
systat 11 TCP
netstat 15 TCP
ftp-data 20 TCP File Transfer Protocol (data)
ftp 21 TCP File Transfer Protocol
smtp 25 TCP Simple Mail Transfer Protocol
time 37 TCP Time Server
time 37 UDP Time Server
name 42 UDP Name Server
whois 43 TCP nicname
domain 53 UDP
domain 53 TCP
tftp 69 UDP
rje 77 TCP
finger 79 TCP
link 87 TCP ttylink
supdup 95 TCP
hostname 101 TCP hostname
pop-2 109 TCP Post Office Protocol
uucp-path 117 TCP
nntp 119 TCP Network News Transfer Protocol
ntp 123 TCP Network Time Protocol

Ports in the region 1-255 are reserved by TCP/IP. The system may reserve more. User processes may have their own ports above 1023. The function getservbyname can be used to find the port for a service that is registered.

Sockets

A socket is a data structure maintained by the system to handle network connections. A socket is created using the call socket. It returns an integer that is like a file descriptor. In fact, under Windows, this handle can be used with the ReadFile and WriteFile functions.

#include <sys/types.h>
#include <sys/socket.h>
int socket(int family, int type, int protocol);

Here, family will be AF_INET for IP communications, protocol will be zero and type will depend on whether TCP or UDP is used. Two processes wishing to communicate over a network create a socket each. These are similar to two ends of a pipe, but the actual pipe does not yet exist.

Connection Oriented (TCP)

One process (server) makes its socket known to the system using bind. This will allow other sockets to find it. It then "listens" on this socket to "accept" any incoming messages. The other process (client) establishes a network connection to it and then the two exchange messages. As many messages as needed may be sent along this channel, in either direction.

Server

Client

Connectionless (UDP)

In a connectionless protocol, both sockets have to make their existence known to the system using bind. This is because each message is treated separately, so the client has to find the server each time it sends a message and vice versa. When bind is called, it binds to a new port. It cannot bind to one already in use. If you specify the port as zero, the system gives you a currently unused port. Because of this extra task on each message send, the processes do not use read/write, but recvfrom/sendto. These functions take as parameters the socket to write to and the address of the service on the remote machine.

Server

Client

Version History

////////////////////////////////////////////////////////////////////////
//    File:        SocketComm.cpp
//    Version:     1.4
//
//  1.0 - Initial release.
//  1.1 - Added support for Smart Addressing mode
//  1.2 - Fixed various issues with address list (in UDP mode)
//  1.3 - Fix bug when sending message to broadcast address
//  1.4 - Add UDP multicast support
////////////////////////////////////////////////////////////////////////

How to Use

This class can be used to create a TCP or UDP socket. Its use is very simple. First of all, the CSocketComm class is not completed by itself for server operation. This class must be derived. Fortunately, only two functions need to be created, OnDataReceived and OnEvent. The default functions don't do anything. Now to create and start a server socket, do the following:

// To use TCP socket
// no smart addressing - we use connection oriented
m_SocketObject.SetSmartAddressing( false ); 
m_SocketObject.CreateSocket( m_strPort, AF_INET, SOCK_STREAM,0); // TCP

// To use UDP socket
m_SocketObject.SetSmartAddressing( true );
m_SocketObject.CreateSocket( m_strPort, 
   AF_INET, SOCK_DGRAM, SO_BROADCAST); // UDP

// Now you may start the server/client thread to do the work for you...
m_SocketObject.WatchComm();

To create and start a client socket, do the following:

// To use TCP socket
m_SocketObject.ConnectTo( strServer, m_strPort, AF_INET, SOCK_STREAM); // TCP

// To use UDP socket
m_SocketObject.ConnectTo( strServer, m_strPort, AF_INET, SOCK_DGRAM); // UDP

// Now you may start the server/client thread to do the work for you...
m_SocketObject.WatchComm();

References

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralA very interesting TCP socket class
brunoleven
14:45 26 Nov '09  
Also have a look at this project:

A Universal TCP Socket Class for Non-blocking Server/Clients
Features
* Very easy to use professional class
* Very clean code
* Can be used in production
* TCP Socket with functionality for Client and Server
* The server allows up to 62 clients to connect at the same time
* Support of multiple network adapters
* The class cSocket is thread safe:
-- 1. It is possible to create one extra thread which processes the events (FD_READ, etc.).
-- 2. It is also possible to run the entire server or client in ONE single thread. The whole application can run only within the GUI thread!
* All functions of the class are non-blocking (asynchronous) and event driven.
* You receive an event on the server when a client has connected or disconnected, and on the client when the server has been shut down (and obviously when data was received).
* Event handling is optimized for servers under stress (near 100% CPU load).
* You don't have to worry about any limited size buffers:
-- SEND: You can send data of any size.
-- RECEIVE: Whenever a new data block is received, it is automatically appended to a dynamic receive memory where data accumulates until you remove it (dynamic FIFO buffer).
* If a client is idle for longer than a user defined maximum time, it gets disconnected from the server.
* The code compiles as UNICODE and MBCS. (Tested on Visual Studio 6, 2003, 2005)
* In the ZIP file, you can find additionally a Winsock FAQ which I compiled into a CHM file. This answers many questions concerning Winsock programing.
* Can be used on Windows CE.


Bruno
GeneralWill this class be useful on communication from 32bit process to 64bit process
Richard Ernstberger
4:46 26 Oct '09  
Hello Ernest,
i'm looking for some sources to implement a communication between a 32bit process and a 64bit process on Vista 64bit.
The description of your class sounds good, so my question: do have used it in such a way or do you know any other that has implemented such a communication?
Thanks in advance for any answer or hint on this topic.
Richard
GeneralRe: Will this class be useful on communication from 32bit process to 64bit process
Ernest Laurentin
19:27 26 Oct '09  
Please use the latest...
Full Multi-thread Client/Server Socket Class with ThreadPool[^]
Supports both 32 and 64-bit

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

AnswerRe: Will this class be useful on communication from 32bit process to 64bit process
brunoleven
14:41 26 Nov '09  
Hello

It is complete nonsense to use such an overbloated class for inter process communication on the same PC.

You should use a named Pipe instead.

Search Google for "Interprocess Communication" and "Named Pipe"!
You will find a lot of code.
And its much easier.
I have written various communications between 32 Bit and 64 Bit processes and I can tell you that it works seamlessly.

Bruno
GeneralTransfer Image ( upto 3MB)
Madhu_Rani
21:26 4 Aug '09  
First of all Thanks for writing such a good piece of code.


I am developing a remote desktop access application like VNC. I used your developed classes to create the client/server application.

I am using the TCP connection by doing m_pCurServer.SetSmartAddressing( false );

The application works fine to sends the smaller images to client (1000 Bytes etc) But it is not working for the larger images ( say upto 3 MB)...

I checked the size of buffer that you provided by declaring in the file socketcomm.h

#ifndef BUFFER_SIZE
#define BUFFER_SIZE MAX_PATH
#endif


But then could not figure out, that what is the size of MAX_PATH... Would you please guide me?
that how I may able to send larger data ( into MB,s) by using these classes....

THANKS.
GeneralRe: Transfer Image ( upto 3MB)
Ernest Laurentin
3:55 5 Aug '09  
Madhu,
BUFFER_SIZE can be changed from your stdafx.h to whatever you want.
If you plan to send 3M over the network, you should use a protocol like FTP, SFTP.
Also, please use latest version of this code:
Full Multi-thread Client/Server Socket Class with ThreadPool[^]

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

GeneralRe: Transfer Image ( upto 3MB)
Madhu_Rani
4:37 7 Aug '09  
thanks.

I did not change the buffer-size, however I assembled the packets on the receiving end. As client receive packets in the size 260, so I assemble all these in the OnReceived.....by introducing START and END tags.
Generalhow to make ServerSocket WriteComm(...) work ?
mhlee0328
0:03 21 May '09  
I appreciate for your nicely demo code.
While I create my own Class CMsgDealer with event trigger....
when I need forward some packets to the socket,call the CServerSocketDlg::OnChMessage(x,x)

//CMsgDealer.h
class CMsgDealer
{
public:
CMsgDealer();
~CMsgDealer();
virtual void OnChMessage(BSTR ChName, BSTR ChMsg); //mhlee add for MOM
}

//CMsgDealer.cpp
void CMsgDealer::OnChMessage(BSTR ChName, BSTR ChMsg)
{
}



//CServerSocketDlg.cpp
void CServerSocketDlg::OnChMessage(BSTR ChName, BSTR ChMsg)
{
//here do the same job like what CServerSocketDlg::OnBtnSend() , I pasted code form OnBtnSend()
//skip......
if (m_SocketManager[i].IsOpen() && m_pCurServer != &amp;m_SocketManager[i])
{
m_SocketManager[i].WriteComm(msgProxy.byData, nLen, INFINITE);
SendToLog("!!!!!!!!m_SocketManager[i].WriteComm(msgProxy.byData, nLen, INFINITE);", MTC_LOG_INFO);
}
//skip
}

why dose m_SocketManager[i].IsOpen() -----> It didn't open!
Some how I try to add PickNextAvailable() before m_SocketManager[i].IsOpen() can't be work too.

Would you please give me some suggestion ? Thanks a lot.
GeneralRe: how to make ServerSocket WriteComm(...) work ?
Ernest Laurentin
5:56 21 May '09  
I'm confused by your question.
Also, please use the update version.
Full Multi-thread Client/Server Socket Class with ThreadPool[^]

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

GeneralConnection Drop Detection
daoc
8:05 12 May '09  
Hi Ernest,
First of all, thank you very much for your code. I'm using your code to save data sent from wireless systems via GPRS service. I'm using TCP mode. Those wireless systems are the clients.
I'm trying to detect when the connection is dropped and use the EVT_CONDROP as a way to detect this. For some reason, the EVT_CONDROP happens but I can still receive the data at the server.
Here are my questions:
1. Do you have any idea why the server detect a connection drop and still able to receive data?
2. What could I do differently to avoid the faulty connection drop detection.

Thank you very much in advance.
-CD
NewsRe: Connection Drop Detection
Ernest Laurentin
10:58 12 May '09  
I haven't used this code for a long time. Can you use the new version?
Full Multi-thread Client/Server Socket Class with ThreadPool[^]

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

General[Message Deleted]
Elmue
7:31 17 Mar '09  

General[Message Deleted]
Elmue
7:27 17 Mar '09  

Questiontwo NICs
abhithakur88
0:29 10 Feb '09  
Hi all,
I have two NICs installed on my computer. I want to open a server port on the specific IP of 1st or 2nd NIC. How?
Thanks in advance
AnswerRe: two NICs
Ernest Laurentin
4:13 10 Feb '09  
The update I sent will let you do that. Please come back soon!

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

GeneralRe: two NICs
tkuzeja
2:17 23 Feb '09  
Is this "NIC-specific" solution implemented throughout the code?   I ask because I still see in some methods the hardcoded selection of the first address reported.   For example in CSocketComm::GetIPAddress I see the returned address being lphostent->h_addr_list[0]. What modifications are necessary to make sure a preferred NIC is being used consistently?
GeneralRe: two NICs
Ernest Laurentin
5:22 23 Feb '09  
You could use IP config utilities. GetAdapterInfo may do what you need.
Did you know I made a revision of this code? You can find it here.

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

GeneralRe: two NICs
tkuzeja
6:30 23 Feb '09  
I'm not sure I clearly explained my problem.   In this article's example as well as the new one you posted, I see the same code in areas where you are retrieving an IP address associated with the connection.

lphostent->h_addr_list[0]   is how it generally appears.

If indeed I have multiple NICs and the one I want to use is NOT at h_addr_list[0], I'm not sure either example will work correctly.   In my case, my wireless adapter always shows up at the [0] entry in the address list.   I want to use a wired adapter for multicast.   I can retrieve the IP of the desired adapter without a problem but I can't seem to set up this adapter for use with your sockets code.   I'm making modifications but am concerned that maybe I don't understand the big picture.

I've tried to do things to eliminate the hardcoded address selection by modifying the code similar to the following...

while (hp->h_addr_list[i])
{
     // Create Address string
     sprintf(test, "%u.%u.%u.%u",
          (UINT)(((PBYTE) hp->h_addr_list[i])[0]),
          (UINT)(((PBYTE) hp->h_addr_list[i])[1]),
          (UINT)(((PBYTE) hp->h_addr_list[i])[2]),
          (UINT)(((PBYTE) hp->h_addr_list[i])[3]));

     TRACE("SocketComm::GetLocalAddress(): h_add_list[%d] = %s\n", i, strHost);

     if (0 == strcmp(test,preferredIp))
     {
          defaultIndex = i;
          break;
     }
     ++i;
}

However, I'm afraid I'm missing something as my multicast is failing to work.
GeneralRe: two NICs
Ernest Laurentin
6:50 23 Feb '09  
OK, I understand better.
You need to use the new class in the other article. Use the IP address that you got as the host address.
That's the reason I updated the interface to make it clearer. The class in this article would not work correctly with multiple adapters.
Try to hardcode the IP address when you call CreateSocket and see if it works

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

Generalauto connect client
abhithakur88
1:00 9 Feb '09  
hi all,
i have a scenario. if client socket is connected to the server socket and due to some reason server connection gets closed. client disconnects automatically. now i want a thread to check whether server is there or not and as and when server socket starts itself again, client socket connects automatically to the server socket.
plz help.
thanks in advance
AnswerRe: auto connect client
Ernest Laurentin
5:27 9 Feb '09  
Create a separate thread and poll the server address. If you are using TCP, when the connection drops, the socket provider will notify you about this event. But for UDP, you won't find out easily because the send will still succeed unless you are binding to 'localhost' address. That is, under Windows when the connection drops for UDP, recvfrom will report the address of the connection (remember localhost only). This doesn't work the same way if you are connected to a real adapter.
Hope that helps!

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

News[Message Deleted]
Elmue
8:46 7 Feb '09  

GeneralRe: Many bugs and inmature code!
Ernest Laurentin
9:27 7 Feb '09  
You are such an arrogant!
This article hasn't been updated since 2004! Wake up!
The real code being shared is the SocketComm class but it seems many people (like you) even want to reuse the "DEMO" code.
A demo is there to help you see how it is used. You should be able to use the socket class in UNICODE and multi-byte project.
I don't have any plan to update this article. Relax, if you have any comment that is not about the demo, I'll be glad to consider.

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

General[Message Deleted]
Elmue
12:26 7 Feb '09  

GeneralRe: Many bugs and inmature code!
Ernest Laurentin
14:32 7 Feb '09  
Elmue wrote:
What is Codeproject worth if the authors never update their old articles ?

Good point! I already looked at what you said and I have seen a typo with MultiByteToWideChar with the code being hosted here. My current version is no longer compatible with what I sent years ago but I'll see what I can do.
See: http://www.codeproject.com/KB/applications/ScriptRunner.aspx[^]
You will find SocketHandle.h, .cpp in the zipfile.
Next time ask nicely and that may save you to googling!

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin


Last Updated 10 Feb 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010