Reputation: 661
I have a client and server, both with methods for receiving and sending, and both are using the same class for packets, packet's header size and deserialization etc.
Everything works if I send smaller packages of just text messages, but when I try to send an image, the buffer overflows and I get an out of memory exception. The strange part is that it actually finds the correct packetsize from the packet's header, but when it then proceeds to reed the packetsize has changed into odd numbers. The image is in form of a byte array inside the packet class.
In the part where it is about to read the actual packet, PacketLength has changed, to either very large numbers or a negative value even. I am trying to understand why it keeps changing despite not looking for the header size anymore..
I am making sure that the server sends just 1 package, and I am also printing the package size before sending, then checking if the client is receiving said packet. The client keeps receiving more than it should.
Please help me out :)
What the server prints out during sending:
What the client prints out during receiving:
(then once the whole packet is read it is added to a list and forwarded to other internal methods to handle the packet based on its type (image, text, etc)
Example with image embedded into the packet:
Server code:
// This is a threaded TCPclient handler on the server.
private void _TCP_ManageClient(object clientObj)
{
uint clientID = _ClientConnected();
var client = (TcpClient) clientObj;
bool connected = true;
_AddClientFromList(ref client, clientID);
NetworkStream stream = client.GetStream();
AddPacketToSend(_Packet_Welcome(clientID)); // Welcome, client #X. message is sent out.
while (connected)
{
// S E N D P A C K E T
SendPacketsInQueue(stream);
if (stream.DataAvailable)
{
// R E C E I V E P A C K E T
ReceivePacketsFromStream(stream);
// R E A D P A C K E T
ReadPacketsInQueue(ref connected);
}
}
if (!connected) { Con.Add(m_Logtag, "Client[" + clientID + "] dropped"); }
}
// Send packets which are in the format of 'RemuseNetPacket' class.
public void SendPacketsInQueue(NetworkStream stream)
{
if (m_SendMessageList.Count > 0)
{
byte[] packetBytes;
byte[] readyData;
int byteCount = 0;
int sentPackets = 0;
for (int i = 0; i < m_SendMessageList.Count; i++)
{
packetBytes = m_SendMessageList[i].Serialize();
Int32 headersize = packetBytes.Length;
byte[] packetLength = BitConverter.GetBytes(headersize);
Con.Add(m_Logtag, "Header size: " + headersize);
Con.Add(m_Logtag, "PacketLength: " + packetLength.Length);
readyData = Extensions.Concatenate(packetLength, packetBytes);
stream.Write(readyData, 0, readyData.Length);
byteCount += readyData.Length;
sentPackets++;
}
Con.Add(m_Logtag, "Sent " + sentPackets + "/" + m_SendMessageList.Count + " packets (" + byteCount + " bytes)");
int r = m_SendMessageList.Count;
m_SendMessageList.Clear();
Con.Add(m_Logtag, "Removed " + r + " sent packages from list");
}
}
Client code:
// This is the client's TCP loop.
private void _TCPClientStart()
{
try
{
TCPClient = new TcpClient();
TCPClient.Connect(m_HostIP, m_Port);
Con.Add(m_Logtag, "Connected to " + m_HostIP + ":" + m_Port);
m_IsRunning = true;
m_Connected = true;
NetworkStream stream = TCPClient.GetStream();
AddPacketToSend(_Packet_Hello()); // Hello, I am [computer name]. message is sent out.
while (m_Connected)
{
if (stream.DataAvailable)
{
// R E C E I V E P A C K E T
ReceivePacketsFromStream(stream);
// R E A D P A C K E T
ReadPacketsInQueue();
}
// S E N D P A C K E T
SendPacketsInQueue(stream);
}
Disconnect();
}
catch (Exception e)
{
Con.Add(m_Logtag, "TCPclient Exception: " + e.ToString());
Con.Add(m_Logtag, "Stacktrace: " + e.StackTrace);
}
}
// Client receives a packet.
private void ReceivePacketsFromStream(NetworkStream stream)
{
int PacketLength = -1;
int BytesRead = 0;
byte[] ReceivedBytes = new byte[0];
while (stream != null && stream.DataAvailable)
{
// Read packet's header (first 4 bytes)
if (PacketLength < 0)
{
if (BytesRead == 0) { ReceivedBytes = new byte[m_HeaderLength]; }
BytesRead += stream.Read(ReceivedBytes, BytesRead, (ReceivedBytes.Length - BytesRead));
if (BytesRead == m_HeaderLength)
{
PacketLength = BitConverter.ToInt32(ReceivedBytes, 0);
// Obtained information about the packet's size.
if (PacketLength < m_MaxPacketSize)
{
Con.Add(m_Logtag, "Received packet header, packet size: " + PacketLength);
BytesRead = 0;
Array.Clear(ReceivedBytes, 0, ReceivedBytes.Length);
}
else
{
Con.Add(m_Logtag, "Received too big packet: " + PacketLength);
}
}
}
// Start reading packet content.
else
{
Con.Add(m_Logtag, "Start reading packet");
if (BytesRead == 0) { ReceivedBytes = new byte[PacketLength]; }
BytesRead += stream.Read(ReceivedBytes, BytesRead, (ReceivedBytes.Length - BytesRead));
// Whole packet obtained.
if (BytesRead >= PacketLength)
{
RemuseNetPacket packet = new RemuseNetPacket();
packet = packet.Desserialize(ReceivedBytes);
Con.Add(m_Logtag, "Received packet #" + packet.ID);
// Add packet to list for reading.
if (packet != null) { AddPacketToRead(packet); }
BytesRead = 0;
PacketLength = -1;
Array.Clear(ReceivedBytes, 0, ReceivedBytes.Length);
}
}
}
}
edit: adding image packet type code
private RemuseNetPacket _Packet_Screen()
{
Con.Add(m_Logtag, "Send Image packet");
RemuseNetPacket p = new RemuseNetPacket();
p.Type = RemusePacketType.Image;
// captures the screen with the mouse (true) using format jpeg.
p.Data = ScreenCapture.CaptureToBytes(true, m_ImageFormat);
Con.Add(m_Logtag, "package img size: " + p.Data.Length);
p.SenderName = m_Name;
p.Timestamp = _GetCurrentTimestamp();
return p;
}
This is what the log says about the weird packet size:
[Active] Host: Send Image packet (this is where i sent 1 image packet)
[Active] Host: removed 1 sent packages from list
[Active] Client: Start reading packet
[Active] Client: Received data: 74456 / 327332 (this is the actual packet size)
[Active] Client: Received packet header, packet size: -251848753 (suddenly it becomes this..)
[Active] Client: Start reading packet
[Active] Client: Received data: 4 / 1251185707
[Active] Client: Received data: 4 / 1251185707
[Active] Client: Received data: 4 / 1251185707
[Active] Client: Received data: 4 / 1251185707
[Active] Client: Received data: 4 / 1251185707
[Active] Client: Received data: 4 / 1251185707
Upvotes: 2
Views: 780
Reputation: 1062705
Hard to diagnose specifically, but here's a more typical read loop for this scenario; a lot simpler and probably easier to debug:
byte[] buffer = new byte[512];
while(true) {
if(!Fill(stream, buffer, 4)) break;
int len = BitConverter.ToInt32(buffer, 0);
if(buffer.Length < len) buffer = new byte[len]; // need moar!
if(!Fill(stream, buffer, len)) throw new EndOfStreamException();
ProcessData(buffer, len); // note: only look at the first "len" bytes
}
static bool Fill(Stream source, byte[] destination, int count) {
int bytesRead, offset = 0;
while(count > 0 &&
(bytesRead = source.Read(destination, offset, count)) > 0)
{
offset += bytesRead;
count -= bytesRead;
}
return count == 0;
}
Upvotes: 2