I'm a C# beginner facing problems regarding sending an image from a client to a server. I use the following code :
Client :
try
{
Bitmap desktopBMP = CaptureScreen.CaptureDesktop();
Image image = (Image)desktopBMP;
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
if (m_clientSocket != null)
{
byte[] data = ms.ToArray();
m_clientSocket.Send(data);
}
}
catch (Exception e)
{
sending = false;
MessageBox.Show(e.Message);
}
Server :
// This the call back function which will be invoked when the socket
// detects any client writing of data on the stream
static int i = 0;
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState;
try
{
// Complete the BeginReceive() asynchronous call by EndReceive() method
// which will return the number of characters written to the stream
// by the client
int iRx = socketData.m_currentSocket.EndReceive(asyn);
byte[] data = new byte[iRx];
data = socketData.dataBuffer;
MemoryStream ms = new MemoryStream(data);
Image image = Image.FromStream(ms);
image.Save(i + socketData.m_clientNumber+".jpg");
i++;
// Continue the waiting for data on the Socket
WaitForData(socketData);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
// Start waiting for data from the client
public void WaitForData(SocketPacket socketPacket)
{
try
{
if (pfnWorkerCallBack == null)
{
// Specify the call back function which is to be
// invoked when there is any write activity by the
// connected client
pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
}
socketPacket.m_currentSocket.BeginReceive(socketPacket.dataBuffer,
0,
socketPacket.dataBuffer.Length,
SocketFlags.None,
pfnWorkerCallBack,
socketPacket
);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
The client sends images at every 100 ms and this works well for a while but sometimes a "ArgumentException" is thrown by the called "System.Drawing.Image.FromStream()" function in the server.
What am I doing something wrong here ? and how should I correct it ?
Thanks
Looking at the MSDN page for Image.FromStream, it states that the parameter is either null or contains an invalid image when that exception is thrown. Can you also send a hash of the image data to the server, which it could then use to validate your image data hasn't been corrupted in transit? If it is corrupt the server could notify the client that it should resend the image. I suspect that you are running so much data that the odds are you are receiving an occasional corrupt bit.
Also add a temporary check just to make sure your socketData.dataBuffer hasn't somehow been set to null while you are debugging this issue.
Related
I was able to send image from server to client . there is two image when one comes after another it display like a video, but now i want to stream a video from my client to server. I want to stream the file from my own localhost.
Sending
private void Start_Sending_Video_Conference(string remote_IP, int port_number)
{
try
{
ms = new MemoryStream();// Store it in Binary Array as Stream
IDataObject data;
Image bmap;
// Copy image to clipboard
SendMessage(hHwnd, WM_CAP_EDIT_COPY, 0, 0);
// Get image from clipboard and convert it to a bitmap
data = Clipboard.GetDataObject();
if (data.GetDataPresent(typeof(System.Drawing.Bitmap)))
{
bmap = ((Image)(data.GetData(typeof(System.Drawing.Bitmap))));
bmap.Save(ms, ImageFormat.Bmp);
}
picCapture.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] arrImage = ms.GetBuffer();
myclient = new TcpClient(remote_IP, port_number);//Connecting with server
myns = myclient.GetStream();
mysw = new BinaryWriter(myns);
mysw.Write(arrImage);//send the stream to above address
ms.Flush();
mysw.Flush();
myns.Flush();
ms.Close();
mysw.Close();
myns.Close();
myclient.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Video Conference Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Receiving
private void Start_Receiving_Video_Conference()
{
try
{
// Open The Port
mytcpl = new TcpListener(6000);
mytcpl.Start(); // Start Listening on That Port
mysocket = mytcpl.AcceptSocket(); // Accept Any Request From Client and Start a Session
ns = new NetworkStream(mysocket); // Receives The Binary Data From Port
picture_comming.Image = Image.FromStream(ns);
mytcpl.Stop(); // Close TCP Session
if (mysocket.Connected == true) // Looping While Connected to Receive Another Message
{
while (true)
{
Start_Receiving_Video_Conference(); // Back to First Method
}
}
myns.Flush();
}
catch (Exception) { button1.Enabled = true; myth.Abort(); }
}
so how should i stream a video file in my client end where the file is in my server.
I'm trying C# sockets to send images. It works, but it's unstable. The images sent through are quite large and are updated very quickly which causes it to flicker every now and then. I'm looking for a way to compress the data sent if possible. I'm using this code:
Server side:
System.IO.MemoryStream stream = new System.IO.MemoryStream();
// !! Code here that captures the screen !!
bitmap.Save(stream, myImageCodecInfo, myEncoderParameters);
byte[] imageBytes = stream.ToArray();
stream.Dispose();
// Send the image
clientSocket.Send(imageBytes);
// Empty the byte array?
for (int i = 0; i < imageBytes.Length; i++)
{
imageBytes[i] = 0;
}
Client side:
private void OnConnect(IAsyncResult ar)
{
try
{
MessageBox.Show("Connected");
//Start listening to the data asynchronously
clientSocket.BeginReceive(byteData,
0,
byteData.Length,
SocketFlags.None,
new AsyncCallback(OnReceive),
null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Stream Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void OnReceive(IAsyncResult ar)
{
try
{
int byteCount = clientSocket.EndReceive(ar);
// Display the image on the pictureBox
MemoryStream ms = new MemoryStream(byteData);
pictureBox1.Image = Image.FromStream(ms);
}
catch (ArgumentException e)
{
//MessageBox.Show(e.Message);
}
clientSocket.BeginReceive(byteData,0,byteData.Length,SocketFlags.None,new AsyncCallback(OnReceive),null);
}
I ended up using gzip.
Turns out the flicker wasn't due to it being updated very quickly, but was because of the way I had sockets set up. It wasn't sending the whole image.
I keep getting an SerializationException whenever I try to deserialize a list of doubles from a NetworkStream:
End of Stream encountered before
parsing was completed
I have a simple client server architecture: my TcpTransportClient wraps the functionality of a TcpClient and I utilize two basic methods: Send (sends a message) and Receive (blocks until a message is received).
The Send function takes a Message, serializes it using a BinaryFormatter and sends the bytes via the NetworkStream.
public void Send(Message message)
{
if (message == null)
{
throw new TransportException("Invalidate Parameter In Send Call");
}
if (_tcpClient == null || !_tcpClient.Connected)
{
throw new TransportException("Client Not Connected");
}
lock (_sync)
{
// Serialzie the message
MemoryStream memStream = new MemoryStream();
_serializer.Serialize(memStream, message);
// Get the bytes of of the memory stream
byte[] buffer = memStream.GetBuffer();
// Write the message to the network stream
NetworkStream networkStream = _tcpClient.GetStream();
networkStream.Write(buffer, 0, buffer.Length);
networkStream.Flush();
}
}
The receive function reads bytes into a buffer from the NetworkStream, then deserializes the message by using a BinaryFormatter:
public Message Receive()
{
if (_tcpClient == null || !_tcpClient.Connected)
{
throw new TransportException("Client Not Connected");
}
byte[] buffer;
MemoryStream memStream = new MemoryStream();
NetworkStream netStream = _tcpClient.GetStream();
try
{
do
{
// Allocate a new buffer
buffer = new byte[_tcpClient.ReceiveBufferSize];
// Read the message buffer
int sizeRead = netStream.Read(buffer, 0, buffer.Length);
// Write the buffer to the memory stream
memStream.Write(buffer, 0, sizeRead);
} while (netStream.DataAvailable);
// Reset the memory stream position
memStream.Position = 0;
// Deserialize the message
object tmp = _deserializer.Deserialize(memStream); // <-- The exception is here!
// Cast the object to a message
return (Message)tmp;
}
catch (System.Exception e)
{
if (_tcpClient == null || !_tcpClient.Connected)
{
throw new TransportException("Client Not Connected");
}
else
{
throw e;
}
}
}
I have a basic sending thread:
TcpTransportClient client = new TcpTransportClient(GetLocalAddress(), servicePort);
client.Connect();
Thread sendThread = new Thread(() =>
{
List<double> dataSet = new List<double>();
for (double d = 0.0; d < 500.0; d++)
{
dataSet.Add(d);
}
while (true)
{
try
{
// Serialize the data set
MemoryStream memStream = new MemoryStream();
BinaryFormatter binFormat = new BinaryFormatter();
binFormat.Serialize(memStream, (object)dataSet);
// Create a message
Message msg = new Message();
// Hold the object bytes in an opaque field
msg.SetFieldValue(1000, memStream.GetBuffer());
// Set the message topic
msg.SetTopic("client.dataSet");
// Send the message
client.Send(msg);
// Sleep
Thread.Sleep(3000);
}
catch (TransportException)
{
break;
}
catch(Exception)
{
//ignore it
}
}
});
sendThread.IsBackground = true;
sendThread.Start();
And a receive thread which gets started whenever a TcpClient is accepted:
public void HandleAcceptedClient(TcpTransportClient client)
{
Thread receiveThread = new Thread(() =>
{
while (true)
{
try
{
Message msg = client.Receive();
Trace.WriteLine("Server Received: " + msg.GetTopic());
byte[] buffer = msg.GetFieldOpaqueValue(1000);
MemoryStream memStream = new MemoryStream(buffer);
BinaryFormatter binFormat = new BinaryFormatter();
List<double> dataSet = (List<double>)binFormat.Deserialize(memStream);
if (dataSet.Count == 500)
{
Trace.WriteLine(DateTime.Now + ": OK");
}
else
{
Trace.WriteLine(DateTime.Now + ": FAIL");
}
}
catch (TransportException)
{
break;
}
catch(Exception)
{
// ignore it
}
}
});
receiveThread.IsBackground = true;
receiveThread.Start();
}
The exception always occurs when I try to deserialize the message in Receive method of my TcpTransportClient, but the problem only occurs if I put some data in the data set. What's the proper way to send a list of values over a network and successfully deserialize them on the receiving end?
P.S. I tried the solution in a nearly identical question, but it didn't work: I'm still getting the same exception.
while (netStream.DataAvailable);
That's not correct. You should stop reading when the Read() call returns 0. The DataAvailable property just tells you whether or not the Read() call will block, waiting to allow the server to catch up.
You need message framing.
I posted a question on how to send large objects over TCP and it seems like the primary issue is solved, but now frequently I get another exception:
Binary stream '0' does not contain a
valid BinaryHeader. Possible causes
are invalid stream or object version
change between serialization and
deserialization.
The issue is still in my Receive method:
public Message Receive()
{
if (_tcpClient == null || !_tcpClient.Connected)
{
throw new TransportException("Client Not Connected");
}
// buffers
byte[] msgBuffer;
byte[] sizeBuffer = new byte[sizeof(int)];
// bites read
int readSize = 0;
// message size
int size = 0;
MemoryStream memStream = new MemoryStream();
NetworkStream netStream = _tcpClient.GetStream();
BinaryFormatter formatter = new BinaryFormatter();
try
{
// Read the message length
netStream.Read(sizeBuffer, 0, sizeof(int));
// Extract the message length
size = BitConverter.ToInt32(sizeBuffer, 0);
msgBuffer = new byte[size];
// Fill up the message msgBuffer
do
{
// Clear the buffer
Array.Clear(msgBuffer, 0, size);
// Read the message
readSize += netStream.Read(msgBuffer, 0, _tcpClient.ReceiveBufferSize);
// Write the msgBuffer to the memory streamvb
memStream.Write(msgBuffer, 0, readSize);
} while (readSize < size);
// Reset the memory stream position
memStream.Position = 0;
// Deserialize the message
return (Message)formatter.Deserialize(memStream); // <-- Exception here
}
catch (System.Exception e)
{
if (_tcpClient == null || !_tcpClient.Connected)
{
throw new TransportException("Client Not Connected");
}
else
{
throw e;
}
}
}
The rest of the code relevant to this example can be found in my original question.
Does anybody know what is causing this exception and how I can avoid it?
Update
Changed the Read to read a maximum of _tcpClient.ReceiveBufferSize bytes at a time, rather than trying to read the full message size (which can be larger than the buffer size) and while the frequency of the Exception decreased slightly, it's still occurring quite often.
Let me suggest you a slight simplification of your code:
public Message Receive()
{
try
{
if (_tcpClient == null || !_tcpClient.Connected)
{
throw new TransportException("Client Not Connected");
}
using (var stream = _tcpClient.GetStream())
using (var reader = new BinaryReader(stream))
{
int size = reader.ReadInt32();
byte[] buffer = reader.ReadBytes(size);
using (var memStream = new MemoryStream(buffer))
{
var formatter = new BinaryFormatter();
return (Message)formatter.Deserialize(memStream);
}
}
}
catch (System.Exception e)
{
if (_tcpClient == null || !_tcpClient.Connected)
{
throw new TransportException("Client Not Connected");
}
throw e;
}
}
Also if you are doing this for fun and/or education purposes then it's ok, but in a real project you should probably consider WCF in order to transmit objects over the wire.
WCF not so good in client-server. Th polling duplex is quite raw technology.
I'm trying to send an image using a TCP socket. The client connects to the server without any problems and start to receive the data. The problem is when I try to convert the stream to an image using FromStream() method, I get an OutOfMemory Exception. Can anyone help me out? Really important!! Here is the code;
client snippet
private void btnConnect_Click(object sender, EventArgs e)
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
TcpClient client = new TcpClient();
client.Connect(ipAddress, 9500);
NetworkStream nNetStream = client.GetStream();
while (client.Connected)
{
lblStatus.Text = "Connected...";
byte[] bytes = new byte[client.ReceiveBufferSize];
int i;
if (nNetStream.CanRead)
{
nNetStream.Read(bytes, 0, bytes.Length);
Image returnImage = Image.FromStream(nNetStream); //exception occurs here
pictureBox1.Image = returnImage;
}
else
{
client.Close();
nNetStream.Close();
}
}
client.Close();
}
server snippet
try
{
IPAddress ipAddress = Dns.Resolve("localhost").AddressList[0];
TcpListener server = new TcpListener(ipAddress, 9500);
server.Start();
Console.WriteLine("Waiting for client to connect...");
while (true)
{
if (server.Pending())
{
Bitmap tImage = new Bitmap(Image URL goes here);
byte[] bStream = ImageToByte(tImage);
while (true)
{
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected");
while (client.Connected)
{
NetworkStream nStream = client.GetStream();
nStream.Write(bStream, 0, bStream.Length);
}
}
}
}
}
catch (SocketException e1)
{
Console.WriteLine("SocketException: " + e1);
}
}
static byte[] ImageToByte(System.Drawing.Image iImage)
{
MemoryStream mMemoryStream = new MemoryStream();
iImage.Save(mMemoryStream, System.Drawing.Imaging.ImageFormat.Gif);
return mMemoryStream.ToArray();
}
Thanks a lot in advanced,
There are a couple of things wrong, including, possibly the protocol you are using. First, the client:
If you expect a single image, there is no need for the while loop
Your client first does a Read which reads some information from the server into the buffer, and then it calls Image.FromStream(nNetStream) which will read incomplete data.
Whenever you read from a stream, keep in mind that a single Read call is not guaranteed to fill your buffer. It can return any number of bytes between 0 and your buffer size. If it returns 0, it means there is no more to read. In your case this also means that your client currently has no way of knowing how much to read from the server. A solution here is to have the server send the length of the image as the first piece of information. Another solution would be to have the server disconnect the client after it has sent the information. This may be acceptable in your case, but it will not work if you need persistent connections (e.g. pooled connections on client side).
The client should look something like this (assuming the server will disconnect it after it sends the data):
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
using (TcpClient client = new TcpClient())
{
client.Connect(ipAddress, 9500);
lblStatus.Text = "Connected...";
NetworkStream nNetStream = client.GetStream();
Image returnImage = Image.FromStream(nNetStream);
pictureBox1.Image = returnImage;
}
Next, the server:
Instead of Pending, you can simply accept the client
The server sends the stream over and over again to the same client, until they disconnect. Instead, send it only once.
The server loop should look something like this:
Bitmap tImage = new Bitmap(Image URL goes here);
byte[] bStream = ImageToByte(tImage);
while (true)
{
// The 'using' here will call Dispose on the client after data is sent.
// This will disconnect the client
using (TcpClient client = server.AcceptTcpClient())
{
Console.WriteLine("Connected");
NetworkStream nStream = client.GetStream();
try
{
nStream.Write(bStream, 0, bStream.Length);
}
catch (SocketException e1)
{
Console.WriteLine("SocketException: " + e1);
}
}
}
This part looks funky to me:
byte[] bytes = new byte[client.ReceiveBufferSize];
int i;
if (nNetStream.CanRead)
{
nNetStream.Read(bytes, 0, bytes.Length);
Image returnImage = Image.FromStream(nNetStream); //exception occurs here
First you read client.ReceiveBufferSize bytes into the "bytes" array, and then you proceed to construct the image from what's left on the stream. What about the bytes you just read into "bytes"?
I recomend you to use this code(I've created it by myself and tested it and it works perfect.):
public void Bitmap ConvertByteArrayToBitmap(byte[] receivedBytes)
{
MemoryStream ms = new MemoryStream(receivedBytes);
return new Bitmap(ms, System.Drawing.Imaging.ImageFormat.Png); // I recomend you to use png format
}
Use this to convert received byteArray to an image.
It seems like your server is sending the image over and over again:
while (client.Connected)
{
NetworkStream nStream = client.GetStream();
nStream.Write(bStream, 0, bStream.Length);
}
If the server can send data fast enough, the client will probably keep receiving it.
Here's a solution :
Server side :
tImage.Save(new NetworkStream(client), System.Drawing.Imaging.ImageFormat.Png);
Cliend side:
byte[] b = new byte[data.ReceiveBufferSize];
client.Receive(b);
MemoryStream ms = new MemoryStream(b);
Image receivedImag = Image.FromStream(ms);
or :
Image receivedImag = Image.FromStream(new NetworkStream(client));