I have a client and server class in C# that uses socket communication. The Server looks like this:
public class AsyncTcpServer
{
private Socket _server_socket;
private Socket _client_socket;
private byte[] _receive_buffer;
private byte[] _send_buffer;
private NetworkStream _ns;
public void Start()
{
try
{
_server_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_server_socket.Bind(new IPEndPoint(IPAddress.Any, 17999));
_server_socket.Listen(0);
_server_socket.BeginAccept(new AsyncCallback(BeginAccept), null);
}
catch(Exception e)
{
Debug.Print(e.Message);
}
}
private void BeginAccept(IAsyncResult ar)
{
try
{
_client_socket = _server_socket.EndAccept(ar);
_receive_buffer = new byte[_client_socket.ReceiveBufferSize];
_send_buffer = new byte[_client_socket.ReceiveBufferSize];
_ns = new NetworkStream(_client_socket);
_client_socket.BeginReceive(_receive_buffer, 0, _receive_buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallback), null);
}
catch(Exception e)
{
Debug.Print(e.Message);
}
}
private void RecieveCallback(IAsyncResult ar)
{
try
{
string text = Encoding.ASCII.GetString(_receive_buffer);
Debug.Print("Server Received: " + text);
}
catch (Exception e)
{
Debug.Print("Unexpected exception: " + e.Message);
}
}
public void Send(byte [] bytes)
{
try
{
_ns.Write(bytes, 0, bytes.Length);
}
catch (Exception e)
{
Debug.Print("Unexpected exception: " + e.Message);
}
}
}
And the client looks like this:
public class AsyncTcpClient
{
private Socket _client_socket;
private byte[] _buffer;
private const int HEADER_SIZE = sizeof(int);
public void Start()
{
_client_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_client_socket.BeginConnect(new IPEndPoint(IPAddress.Loopback, 17999), new AsyncCallback(ConnectCallback), null);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
_client_socket.EndConnect(ar);
_buffer = new byte[_client_socket.ReceiveBufferSize];
StartReceive();
byte[] buffer = Encoding.ASCII.GetBytes("Connected!");
_client_socket.Send(buffer);
}
catch (Exception e)
{
Debug.Print(e.Message);
}
}
private void StartReceive(int offset = 0)
{
try
{
_client_socket.BeginReceive(_buffer, offset, _buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallback), null);
}
catch (Exception e)
{
Debug.Print(e.Message);
}
}
private void RecieveCallback(IAsyncResult ar)
{
try
{
int bytes_processed = 0;
int bytes_read = _client_socket.EndReceive(ar);
if (bytes_read > 0)
{
NetworkStream ns = new NetworkStream(_client_socket);
while (ns.DataAvailable && (bytes_processed < bytes_read))
{
byte[] len_bytes = new byte[HEADER_SIZE];
ns.Read(len_bytes, 0, HEADER_SIZE);
int current_chunk_size = BitConverter.ToInt32(len_bytes, 0);
if (current_chunk_size > 0)
{
byte[] data_buff = new byte[current_chunk_size];
ns.Read(data_buff, 0, current_chunk_size);
string s = Encoding.ASCII.GetString(data_buff);
bytes_processed += (HEADER_SIZE + current_chunk_size);
Debug.WriteLine(s);
}
}
}
StartReceive();
}
catch (Exception e)
{
Debug.Print(e.Message);
}
StartReceive();
}
}
They work together as follows:
- Server starts
- Client connects
- Server sends custom packets to the client for its comsumption
I use the following 'data structure' to package my transmission data on the server side to send to the client:
{[DATA_LENGTH_IN_BYTES][PAYLOAD_BYTES]}
On the client side, I parse the first 4 bytes (sizeof(int)) to determine the payload length and then parse the payload itself. This works the first time I do it but after that the DataAvailable
member of the NetworkStream
is false and I can't parse the rest of the payload.
Why is DataAvailable
false? I'm pretty new to doing this stuff in C# - am I approaching it the wrong way entirely?
Thanks in Advance!
I think you forget the EndReceive in the RecieveCallback. (server code)
I advise to create one class that reads/writes to sockets (implementing the protocol). A Base class that handles reads/writes to Sockets, a client socket that is derived from the SocketConnection, but first will connect to an ipendpoint. A server that has a List of SocketConnection. This way you keep your client/server functionality separated of the message handling on socket. But both using the same code to receive/send messages. Here is an example:
Pseudo:
UPDATE:
"Regarding how to handle buffers, what would you suggest as the best way to not miss data in separate packets?"
I would send a size first:
This will separate different packets.
Asynchronous example:
You still need to add some exception handling code.
Example how to use it:
Here is the solution I settled on:
Server:
And the client:
Where messages from the server to the client are formed as follows:
I like this alternative for its simplicity. Its a lot shorter and (to me at least) much easier to manage.
HTH