Listen.Update
The Read
function reading in streams does not guarantee that all data sent at once is read. This happens to improve performance in streams. As the data packets get to the client, they are made available for reading.
When you call the Read
function, it only returns immediately if a packet of data has already arrived to the client over the connection, otherwise it goes into standby mode and awaits the arrival of a packet. This routine can take several rounds.
The Read
function will read the available data up to a certain length (buffer length, 1024 in this case) and return the number of bytes read. If data is not available for reading, the Read
function will go into standby until it reaches the time set in ReadTimout
or a packet arrives. If ReadTimout
is reached, an exception will be thrown. And if the stream or connection is terminated, the Read
function will return 0 (zero), indicating that there is no more data to read.
Therefore, you will need to close the stream or connection to indicate that the data has been completely sent.
public static void UpdateClient(UserConnection client) {
System.IO.MemoryStream mStream = new System.IO.MemoryStream(client.TCPClient.Available);
System.Net.Sockets.NetworkStream nStream = client.TCPClient.GetStream();
byte[] buffer = new byte[1024];
try {
while(true) {
int nBytes = nStream.Read(buffer, 0, 1024);
if(nBytes <= 0)
break;
mStream.Write(buffer, 0, nBytes);
}
} catch {
int code = System.Runtime.InteropServices.Marshal.GetExceptionCode();
Console.WriteLine("Erro Num: " + code);
return;
}
buffer = mStream.ToArray();
string data = null;
data = Encoding.UTF8.GetString(buffer);
Console.WriteLine("Data is: " + data);
Console.WriteLine("Size is: " + data.Length);
Server.Network.ReceiveData.SelectPacket(client.Index, data);
client.TCPClient.GetStream().Flush();
}
A good practice is to define a protocol for flow control, even if simple. As an example, we can agree that before sending any information, the server will send 4 bytes (32 bits) indicating the amount of bytes that will compose the next information.
public static byte[] ReadBytes(System.IO.Stream stream, int size) {
if (size <= 0)
throw new ArgumentOutOfRangeException();
byte[] buffer = new byte[size];
int i = 0;
while (size > 0) {
int nBytes = stream.Read(buffer, i, size);
if (nBytes <= 0)
break;
i += nBytes;
size -= nBytes;
}
if(size > 0) {
byte[] nBuffer = new byte[buffer.Length - size];
Array.Copy(buffer, 0, nBuffer, 0, nBuffer.Length);
buffer = nBuffer;
}
return buffer;
}
public static void UpdateClient(UserConnection client) {
System.Net.Sockets.NetworkStream nStream = client.TCPClient.GetStream();
byte[] buffer = null;
try {
int size = BitConverter.ToInt32(ReadBytes(nStream, 4), 0);
if (size <= 0)
throw new InvalidOperationException();
buffer = ReadBytes(nStream, size);
if(buffer.Length != size)
throw new InvalidOperationException();
} catch {
int code = System.Runtime.InteropServices.Marshal.GetExceptionCode();
Console.WriteLine("Erro Num: " + code);
return;
}
string data = null;
data = Encoding.UTF8.GetString(buffer);
Console.WriteLine("Data is: " + data);
Console.WriteLine("Size is: " + data.Length);
Server.Network.ReceiveData.SelectPacket(client.Index, data);
client.TCPClient.GetStream().Flush();
}