Reputation: 3823
I try to send a live video stream from a webcam over TCP. I compress the images with JPG before sending; that works fine. But I have some problem with the receiver socket. It somehow only get a quarter of the full images on the receiving side.
It looks like this after decoding the byte array I receive:
I have yet programmed the following code to receive the image data (receive
runs within a thread):
private void receive() {
try {
while(running) {
if((available = clientSocket.Receive(buffer, 4, SocketFlags.None)) >= 0) {
int bytesToRead = BitConverter.ToInt32(buffer, 0);
using(MemoryStream ms = new MemoryStream(bytesToRead)) {
using(BinaryWriter bw = new BinaryWriter(ms)) {
while(bytesToRead > 0) {
if((available = clientSocket.Receive(buffer, getRemainingBytes(bytesToRead), SocketFlags.None)) >= 0) {
bw.Write(buffer);
bytesToRead -= available;
}
}
NetworkPacket.deserialize(ms.ToArray());
}
}
}
}
} catch(Exception ex) {
Logger.Log(Level.WARNING, "Could not receive data from TCP server.", ex);
}
}
private int getRemainingBytes(int bytesToRead) {
if(bytesToRead > clientSocket.ReceiveBufferSize) {
return clientSocket.ReceiveBufferSize;
} else {
return bytesToRead;
}
}
As you can guess, the first 4 bytes (Int32) of my message structure defines the packet length I will have to read in for each image (these are between 30-40kB).
What happens behind the scene with the remaining data if I read only the first 4 bytes of the buffered data with clientSocket.Receive(buffer, 4, SocketFlags.None)
? Is it okay to read them in the second ´clientSocket.Receive(...)´ call or are the remaining bytes from the first call dropped when ´clientSocket.Receive(...)´ is called the second time?
How could I improve the receiver code under the assumption that about 30 images per second arrive each 30-40kB in size ?
Upvotes: 0
Views: 934
Reputation: 35477
FIX
You should only "write" the bytes that you receive
Change bw.Write(buffer)
to
bw.Write(buffer, 0, available);
Speedup
Instead of moving the received data between multiple buffers, you could directly read the network data into your buffer.
int bytesToRead = BitConverter.ToInt32(buffer, 0);
int offset = 0;
byte[] frame = new byte[bytesToRead];
while (bytesToRead > 0)
{
var n = clientSocket.Receive(frame, offset, bytesToRead);
offset += n;
bytesToRead -= n;
}
NetworkPacket.deserialize(frame);
Upvotes: 2