TcpClient and images

G

Guest

Hi,

I'm writing a client/server application in which the client send a series of
screenshots to the server to be saved using the tcpclient.
in most cases the first screenshot is transmitted ok and arrives at the
server but from after that i only a couple of KB from the start of the file
which cases the picture to display only the very top (of the screen).
All the pictures are saved at the client side before sent to the server and
they are always good and "full", so the problems seem to be from the
transmition part or after that.

please help ...


****** Server Code:
Const portNo As Integer = 8080
Dim localAdd As System.Net.IPAddress = System.Net.IPAddress.Any
Dim listener As New TcpListener(localAdd, portNo)
listener.Start()

Dim tcpClient As TcpClient

tcpClient = listener.AcceptTcpClient()

tcpClient.ReceiveBufferSize = 400000

Dim lingerOption As New LingerOption(True, 10)
tcpClient.LingerState = lingerOption

Dim NWStream As NetworkStream = tcpClient.GetStream

Dim bytesToRead(200000) As Byte
Dim numBytesRead As Integer = 0

'---read incoming stream
If NWStream.CanRead Then
Do
numBytesRead = numBytesRead + NWStream.Read(bytesToRead,
numBytesRead, tcpClient.ReceiveBufferSize)
Loop While NWStream.DataAvailable
NWStream.Close()
End If

Dim FileName = DateTimeForFile() & ".jpg"
Dim fs As System.IO.FileStream
fs = New System.IO.FileStream(FileName,
System.IO.FileMode.Create, _
System.IO.FileAccess.Write)
fs.Write(bytesToRead, 0, numBytesRead)
fs.Close()

MsgBox(numBytesRead)

tcpClient.Close()

listener.Stop()


****** Client Code:
Dim FileName = DateTimeForFile() & ".jpg"
< Code to save the screenshot on the client>
Dim tcpClient As New System.Net.Sockets.TcpClient
tcpClient.Connect(Me.TextBox_Server.Text, portNo)
Dim NWStream As NetworkStream = tcpClient.GetStream
Dim fs As FileStream
fs = New FileStream(FileName, FileMode.Open, FileAccess.Read)
Dim bytesToSend(fs.Length) As Byte
Dim numBytesRead As Integer = fs.Read(bytesToSend, 0,
bytesToSend.Length)
fs.Close()
NWStream.Write(bytesToSend, 0, numBytesRead)
tcpClient.Close()
 
M

Markus Minichmayr

Hi!

There are three things i found in your code which could be related to your
problem.

1. On the client side you try to read the whole file content in one call to
the Stream.Read method. It is not guaranteed, that the whole data block is
read at once (I think that's even true for FileStream). You should examine
the number of bytes actually read and retry reading until the whole file has
been read.

2. If you read the data comming from the network faster then it arrives,
then I think that NetworkStream.DataAvailable can return false even if
further data will be received. Have you thought about sending some sort of
header with each image, containing the actual image size?

3. In applications that maintain multiple open NetworkStreams I observed
that setting receive buffers above a specific size resulted in blocking
streams. No data could be received at all. The threshold I found was
somewhere at 80KB (as far as I remember) for the sum of all NetworkStream
receive buffers. I'm not sure whether (and in fact I don't think that) this
also is an issue with a single connection but nevertheless you could try to
reduce your receive-bfufer size.

Cheers
- Markus
 
G

Guest

1. I've checked the reading of the file and saw that always to read command
reads the whole file in one call.
2. I tried to limit the reading from the stream based on the file size and
not by the dataavailble property and that fixes the problem - but i don't
know how to send the file size from the client to the server ?
 
M

Markus Minichmayr

In your scenario the easiest way to do this is to use System.IO.BinaryWriter
and System.IO.BinaryReader. Do something like the following (C# Syntax):

Sender:
....
using (BinaryWriter imageWriter = new BinaryWriter(outputStream))
{
imageWriter.Write((uint) MagicNumber); // You should use a magic
number to detect communication errors
imageWriter.Write((uint) ProtocolVersion); // You might want to
include a version number of your protocol
imageWriter.Write((int) imageBytes.Length); // Write the image size
imageWriter.Write(imageBytes); // Write the actual
image
}
....


Receiver:

....
byte[] imageBytes;

using (BinaryReader imageReader = new BinaryReader(inputStream))
{
uint magicNumber = imageReader.ReadUInt32();
uint protocolVersion = imageReader.ReadUInt32();

... check magic number and protocol version and do error handling ...

int imageSize = imageReader.ReadInt32();
imageBytes = imageReader.ReadBytes(imageSize); // The full
data block will be read here.
}

.... do whatever you want ...


Don't forget to handle communication errors like timeouts!

- Markus
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top