Trial By Error

TCP Socket Programming in C#

By March 28, 2017 No Comments

The last couple of weeks, I had been researching socket programming for our VR Conference project. Unity Networking and Photon both have bandwidth limitations that is preventing us to sharing desktops and other assets, so we needed to write a custom solution.  I did what you are doing… googled.  Most of the examples out there are for small amounts of data.

Take a look at the example from Microsoft:

https://msdn.microsoft.com/en-us/library/w89fhyex(v=vs.110).aspx

From the synchronous client example:

You create a new connection (check)
// Create a TCP/IP  socket.
Socket sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );

From <https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx>

Then encode and send your data
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes("This is a test<EOF>");

// Send the data through the socket.
int bytesSent = sender.Send(msg);

From <https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx>

Pretty simple, right?  You think you’re sending a simple packet of data to your server.  But under the hood, your data packet could be broken up into various sized TCP packets.
If this is all you want to send, the server will get it and this example works just fine.

But if you need to send more, you’ll need to allocate a set number bytes to let the server know the size of the data you are transmitting, then read your buffer until you have it all.


 private void ReadCallback(IAsyncResult result)

{

 Socket socket = (Socket) result.AsyncState;

 try

 {

 int bytesRecieved = socket.EndReceive(result);

 _applicationPacketSize = GetApplicationPacketSize(_listenerBuffer); //returns the value from the first 4 bytes

 if (_applicationPacketSize == 0)

 {

 _tcpClient.Client.BeginReceive(_listenerBuffer, _offset, _listenerBuffer.Length - _offset, SocketFlags.None, new AsyncCallback(ReadCallback), _tcpClient.Client);

 return;

 }

 _offset += bytesRecieved;

 OnLogOutput(">> Read {0} bytes of data... new offset: {1}, application packet size: {2}", bytesRecieved, _offset, _applicationPacketSize);

 //Keep reading data until we reach _applicationPacketSize

 //if (_offset < _applicationPacketSize) //keep going, fill buffer

 if (_offset >= _applicationPacketSize) //we got it all and it's complete, the next bytes will be for a new packet

 {

 _offset -= _applicationPacketSize; //start over

 try

 {

 int packetSize = GetApplicationPacketSize(arr);
 //remove the HTS Header bytes

 byte[] data = new byte[packetSize - DATA_OFFSET];
 Array.Copy(arr, DATA_OFFSET, data, 0, data.Length);
 //You can marshal your data to deserialize it to a class
 } 
catch 
{

 OnLogOutput("Unable to deserialize the packet");

 }

 if (_offset > _applicationPacketSize) // We have a completed packet, but we have more bytes for the next packet

 {

 byte[] tmp = new byte[MAX_BUFFER_SIZE];

 Array.Copy(_listenerBuffer, _applicationPacketSize, tmp, 0, _offset);

 _listenerBuffer = tmp;

 }

 }

 _tcpClient.Client.BeginReceive(_listenerBuffer, _offset, _listenerBuffer.Length - _offset, SocketFlags.None, new AsyncCallback(ReadCallback), _tcpClient.Client);

 } 
catch (ObjectDisposedException exs)  //Socket has been closed.
{

 Disconnect();

} 
catch (Exception ex)
 {

 OnLogOutput(">> Error: {0}", ex.Message);

 _tcpClient.Client.BeginReceive(_listenerBuffer, _offset, _listenerBuffer.Length - _offset, SocketFlags.None, new AsyncCallback(ReadCallback), _tcpClient.Client);

 return;

 }

} 

 

Hope this help with your socket programming.

Bitnami