Communicating through sockets

A Socket is an end-point of a bidirectional communication link between two applications running on the same network. So basically it means you can use it to allow applications to communicate with each other. You have a server, that listens for incoming connections, and clients that make a connection to the server. Then, data can be transferred between the clients and the server.

First create a console application and call it SocketServer. The main looks like:

class Program
{
private static System.Net.Sockets.Socket _socket;
private static AsyncCallback _dataTransferCallBack;
private const int MaxLengthOfPendingConnectionsQueue = 10;
private const short SocketPort = 7761;



static void Main(string[] args)
{
_socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
var endPoint = new IPEndPoint(IPAddress.Any, SocketPort);
_socket.Bind(endPoint);
_socket.Listen(MaxLengthOfPendingConnectionsQueue);
// Begins an asynchronous operation to accept an incoming
// connection attempt.
_socket.BeginAccept(OnConnectRequest, null);
Console.WriteLine("Server started, listening...");
Console.ReadLine();
// Clean up socket.
_socket.Close();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}

The socket is created, and bound to an endpoint at a specific port number. Then the BeginAccept operation makes the application wait for an incoming connection request (asynchronously). If a connection request comes in, then the OnConnectRequest operation is executed:

 
public static void OnConnectRequest(IAsyncResult asyn)
{
try
{
// EndAccept completes a call to BeginAccept.
// It returns a new Socket that can be used to send data
// to and receive data from the remote host.
var dataTransferSocket = _socket.EndAccept(asyn);
WaitForData(dataTransferSocket);
_socket.BeginAccept(OnConnectRequest, null);
}
catch (ObjectDisposedException)
{
Console.WriteLine("OnConnectRequest: Socket has been closed.");
}
catch (SocketException ex)
{
Console.WriteLine(
string.Format("Something fishy happened: {0}", ex.Message));
throw;
}
}

In this operation we first call the WaitForData operation, and then call the BeginAccept operation again to continue listening to incoming connection requests of other clients. The WaitForData starts the actual receive of data: if the connected client sends data, the OnDataReceived callback operation is executed:

public static void WaitForData(System.Net.Sockets.Socket dataTransferSocket)
{
try
{
if (_dataTransferCallBack == null)
{ _dataTransferCallBack = OnDataReceived; }
var socketPacket = new SocketPacket(dataTransferSocket);
// Now start listening for data.
dataTransferSocket.BeginReceive(socketPacket.DataBuffer, 0,
socketPacket.DataBuffer.Length, SocketFlags.None,
_dataTransferCallBack, socketPacket);
}
catch (SocketException ex)
{
Console.WriteLine(
string.Format("Something fishy happened: {0}", ex.Message));
throw;
}
}
 
Where SocketPacket is like:
 
public class SocketPacket
{
public System.Net.Sockets.Socket Socket { get; set; }
public byte[] DataBuffer { get; set; }

public SocketPacket(System.Net.Sockets.Socket socket)
{
Socket = socket;
DataBuffer = new byte[1024];
}
}

In the OnDataReceived operation we check if there is data, if there is, we keep calling the WaitForData again to get the next data. If there is no data anymore, we stop the transfer and close the socket:
 
public static void OnDataReceived(IAsyncResult asyn)
{
try
{
var socketPacket = (SocketPacket)asyn.AsyncState;
int numberOfBytesReceived = socketPacket.Socket.EndReceive(asyn);

if (numberOfBytesReceived <= 0)
{
Console.WriteLine("Client {0}, disconnected",
socketPacket.Socket.RemoteEndPoint);
socketPacket.Socket.Close();
return;
}

var receivedData = Encoding.ASCII.GetString(socketPacket.DataBuffer,
0, numberOfBytesReceived);
Console.WriteLine("{0}", receivedData);
WaitForData(socketPacket.Socket);
}
catch (ObjectDisposedException)
{
Console.WriteLine("OnConnectRequest: Socket has been closed.");
throw;
}
catch (SocketException ex)
{
Console.WriteLine(
string.Format("Something fishy happened: {0}", ex.Message));
throw;
}
}

Now what’s left is to write the client side code to connect to the server and send messages. Create a new console application and call it SocketClient. For the client, I’m going to write a SocketPublisher that contains all the logic to connect and send the messages, which is used by the client. This is the code:
 
public interface ISocketPublisher
{
void SendMessage(string message);
}

public class SocketPublisher : ISocketPublisher, IDisposable
{
private System.Net.Sockets.Socket _socket;
private readonly string _remoteAddress;
private readonly short _remotePortNumber;

public SocketPublisher(string remoteAddress,
short remotePortNumber)
{
_remoteAddress = remoteAddress;
_remotePortNumber = remotePortNumber;
Connect();
}

public void SendMessage(string message)
{
var messageBytes =
System.Text.Encoding.ASCII.GetBytes(message);
_socket.Send(messageBytes);
}

public void Dispose()
{
Disconnect();
}

private void Disconnect()
{
if (_socket != null)
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
}

private void Connect()
{
if ((_socket == null) || (!_socket.Connected))
{
var remoteIpAddress =
System.Net.IPAddress.Parse(_remoteAddress);
var remoteEndPoint = new System.Net.IPEndPoint(
remoteIpAddress, _remotePortNumber);
_socket = new System.Net.Sockets.Socket(
AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
_socket.Connect(remoteEndPoint);
}
}
}

And in the Main you can then send a message as follows:
 
class Program
{
private const string SocketAddress = "127.0.0.1";
private const short SocketPort = 7761;

static void Main(string[] args)
{
using (var socketPublisher =
new SocketPublisher(SocketAddress, SocketPort))
{
socketPublisher.SendMessage("Hello world!");
}
}
}

Now start the server, then start the client, and you should see the message coming through at the server:

socket

The server can also send messages back to the clients; if you want to do that you need to keep track of connected clients sockets and then you can send messages back.
 
 
 
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s