I've implemented this C# client which communicate with asynchronous connection to another server I've created in Java. This is the client:
public class NetworkTransaction
{
private GenericRequest request;
private const string serverName = "192.168.1.101";
private const int serverPort = 7777;
private const int TIMEOUT_MILLISECONDS = 3000;
private Delegate method;
public NetworkTransaction(GenericRequest request, Delegate method)
{
this.request = request;
this.method = method;
}
public void SendRequest()
{
SocketAsyncEventArgs connectionOperation = new SocketAsyncEventArgs();
DnsEndPoint hostEntry = new DnsEndPoint(serverName, serverPort);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
connectionOperation.Completed += new EventHandler<SocketAsyncEventArgs>(SocketEventArg_Completed);
connectionOperation.RemoteEndPoint = hostEntry;
connectionOperation.UserToken = socket;
try
{
socket.ConnectAsync(connectionOperation);
}
catch (SocketException ex)
{
throw new SocketException((int)ex.ErrorCode);
}
}
private void SocketEventArg_Completed(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect:
ProcessConnectCompleted(e);
break;
case SocketAsyncOperation.Receive:
ProcessReceiveCompleted(e);
break;
case SocketAsyncOperation.Send:
ProcessSendCompleted(e);
break;
default:
throw new Exception("Invalid operation completed");
}
}
private void ProcessConnectCompleted(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
byte[] buffer = Encoding.UTF8.GetBytes(request.ToJson() + "\n\r");
e.SetBuffer(buffer, 0, buffer.Length);
Socket sock = e.UserToken as Socket;
sock.SendAsync(e);
}
}
private void ProcessSendCompleted(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
Socket sock = e.UserToken as Socket;
sock.ReceiveAsync(e);
}
}
private void ProcessReceiveCompleted(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
Socket sock = e.UserToken as Socket;
sock.Shutdown(SocketShutdown.Send);
sock.Close();
method.DynamicInvoke(dataFromServer);
}
}
}
What can I do to get long messages from the server? What do I need to change in order to make the client try and read more data to see if I actually read the entire message? Since there might be a problem with the line: string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
which receives only a part of the message and not the entire one.
What do i need to change in order to make the client try and read more data to see if i actually read the entire message?
You have to implement a protocol that says "Here come 50 bytes" or "This was all data, goodbye".
ProcessReceiveCompleted()
will be called whenever a piece of data is received, this can be anything between one and a lot of bytes. Sockets do not guarantee a "message" to be sent as a whole, since messages don't exist at that level. The amount of data received is dependant on factors like CPU and network utilization.
That's where your protocol comes in. This has to be defined in both server and client. HTTP, for example, uses two CRLF
's to let the client say "This was my request, please respond now". The server, on the other hand, (by default) closes the connection when all data is sent, but also sends a Content-length
header, so the client can verify it has received all data.
So you'll have to store the data in ProcessReceiveCompleted()
and start processing when you have received a whole message.