I've been trying to send a byte array from client to server to build a authentication server.
I have send the byte array succesfully using the Microsoft asynchronous server socket example. link But in their example they are using string to indiate end of byte transfer.
content.IndexOf("<EOF>") > -1
I don't like this approach and removed it, so the server keeps waiting for a messages from the client until the client or server packet handler decides to close the socket.
I don't understand the need of a string to indicate the end of transfer. I can check this by array length? Is the approach I am using safe enough to ensure the data integrity?
My code server side: The changes are made in the method: ReadCallback
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening(String hostname, int port)
{
// Establish the local endpoint for the socket.
// The DNS name of the computer
// example running the listener is "localhost".
IPHostEntry ipHostInfo = Dns.GetHostEntry(hostname);
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket listener = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
try
{
// Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint);
listener.Listen(100);
// Do not stop after one connection
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Listening for new connection");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before listening again
// for a new connection.
allDone.WaitOne();
Console.WriteLine("Connection established.");
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
//int bytesRead = handler.EndReceive(ar);
// New way, handles forcibly disconnect.
SocketError errorCode;
int bytesRead = 0;
try
{
bytesRead = handler.EndReceive(ar, out errorCode);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
PacketHandler.CheckPacket(
handler: handler,
data: state.buffer,
length: bytesRead
);
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content);
// Keep listening to the socket for messages while the socket is connected.
if (handler.Connected)
{
// Empty the previous message
state.sb.Clear();
try
{
// Recursieve? Calling itself til socket is disposed off.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Thread.Sleep(1000);
}
// If it got this far, means socket is closed. Double checking before disposing of the socket.
if (!handler.Connected)
{
try
{
// https://stackoverflow.com/questions/4160347/close-vs-shutdown-socket
handler.Shutdown(SocketShutdown.Both);
handler.Close();
Console.WriteLine("Closed socket");
}
catch (Exception ex)
{
Console.WriteLine("Failed close socket. " + ex.Message);
}
}
//if (content.IndexOf("<EOF>") > -1)
//{
// // All the data has been read from the
// // client. Display it on the console.
// Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
// content.Length, content);
// // Echo the data back to the client.
// Send(handler, content);
//}
//else
//{
// // Not all data received. Get more.
// handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
// new AsyncCallback(ReadCallback), state);
//}
}
}
public static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}