I'm having trouble sending multiple images over a NetworkStream. My code attempts to maintain a connection with the server as it waits for the command to send an image.
Client Code:
TcpClient client = new TcpClient();
client.Connect(HOSTNAME, PORT);
while (true)
{
NetworkStream stream = client.GetStream(); // <-- Exception thrown here
WaitCmd(stream, "deskcap"); // Waits until the command "deskcap" is received from the server
Bitmap capture = CaptureDesktop();
MemoryStream ms = new MemoryStream();
capture.Save(ms, ImageFormat.Jpeg);
byte[] imageBuffer = ms.GetBuffer();
stream.Write(imageBuffer, 0, (int)ms.Length);
stream.Close();
}
Server Code:
private void desktopButton_Click(object sender, EventArgs e)
{
TcpItem c = (TcpItem)clientsComboBox.SelectedItem;
NetworkStream stream = c.client.GetStream();
string cmd = "deskcap";
byte[] buffer = Encoding.Default.GetBytes(cmd);
stream.Write(buffer, 0, buffer.Length);
Image img = Image.FromStream(stream);
img.Save(#"C:\Users\" + username + #"\Captures\capture" + DateTime.Now.ToBinary() + ".jpg", ImageFormat.Jpeg);
}
Exception:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.dll
Additional information: The operation is not allowed on non-connected sockets.
Update
I added the ability for the client to send the size of the image before the server attempts to receive it. Images are now coming through somewhat corrupted.
Updated Client Code:
TcpClient client = new TcpClient();
client.Connect(HOSTNAME, PORT);
NetworkStream stream = client.GetStream();
while (true)
{
WaitCmd(stream, "deskcap"); // Waits until the command "deskcap" is received from the server
Bitmap capture = CaptureDesktop();
MemoryStream ms = new MemoryStream();
capture.Save(ms, ImageFormat.Jpeg);
byte[] imageArr = ms.ToArray();
byte[] sizeHeader = BitConverter.GetBytes(imageArr.Length);
stream.Write(sizeHeader, 0, sizeHeader.Length); // Should always write four bytes
stream.Write(imageArr, 0, imageArr.Length);
}
stream.Close();
Updated Server Code:
private void desktopButton_Click(object sender, EventArgs e)
{
TcpItem c = (TcpItem)clientsComboBox.SelectedItem;
NetworkStream stream = c.client.GetStream();
string cmd = "deskcap";
byte[] cmdBuffer = Encoding.Default.GetBytes(cmd);
stream.Write(cmdBuffer, 0, cmdBuffer.Length);
byte[] sizeBuffer = new byte[4];
stream.Read(sizeBuffer, 0, 4); // Read a four byte header that contains the size of the image
uint size = BitConverter.ToUInt32(sizeBuffer, 0);
byte[] imageBuffer = new byte[size];
stream.Read(imageBuffer, 0, (int)size);
MemoryStream ms = new MemoryStream(imageBuffer);
Image img = Image.FromStream(ms);
img.Save(#"C:\Users\" + username + #"\Captures\capture" + DateTime.Now.ToBinary() + ".jpg", ImageFormat.Jpeg);
}
Image:
Related
I wrote a tcp listener to receive a sequence of images from single client , this is the code of server :
new Thread(() =>
{
while (true)
{
displayingFrame.Start(); // another thread to display images
Socket socket = listener.AcceptSocket();
TcpClient client = new TcpClient();
client.Client = socket;
Debug.WriteLine("Connection accepted.");
var childSocketThread = new Thread(() =>
{
NetworkStream ns = client.GetStream();
BinaryReader br = new BinaryReader(ns);
while (true)
{
using (MemoryStream ms = new MemoryStream())
{
int length = br.ReadInt32();
Debug.WriteLine("length : " + length);
byte[] buf = new byte[1024];
int totalReaded = 0;
int readed = 0;
while (totalReaded < length)
{
readed = br.Read(buf, 0, buf.Length);
ms.Write(buf, 0, readed);
totalReaded += readed;
}
byte[] frame = ms.ToArray();
this.frames.Enqueue(frame);
Debug.WriteLine("frame enqueued with length " + frame.Length);
}
}
});
childSocketThread.Start();
}
}).Start();
it receive frames very well but suddenly br.ReadInt32(); returns a very big length so br.Read(buf, 0, buf.Length); takes a very long time writing to memory stream and it writes a wrong data inside frame .
this is the client :
TcpClient client = new TcpClient();
client.Connect(new IPEndPoint(IPAddress.Loopback, 20000));
NetworkStream ns = client.GetStream();
BinaryWriter bw = new BinaryWriter(ns);
while ( true )
{
byte[] frame = Screenshot();
bw.Write(frame.Length);
Console.WriteLine("a frame length has flushed : " + frame.Length);
bw.Write(frame);
Console.WriteLine("a frame itself has flushed");
}
Console.ReadKey();
and here the debug info :
If you check the hex value you're getting - 1196314761 - you'll get 0x474E5089 and finally convert to ASCII you will get GNP\x89 which gives us the known magic value \x89PNG that is the marker of PNG file. You're actually reading the content of your screenshot as the length.
Make sure that you're code for reading the data does not read too much from the previous frame. I think you code for reading the data does not include the fact that you might get content of 2 frames in one .Read but then later you just don't care if you have too much data. You only check if it's not less than length.
Server program C#
private TcpListener serverSocket;
..
init:
serverSocket = new TcpListener(ipAddress, port_number);
when new connection request found:
TcpClient clientSock = default(TcpClient);
clientSock = serverSocket.AcceptTcpClient();
NetworkStream networkStream = clientSocket.GetStream();
String FileName = requested binary data file name from client
Byte[] sendBytes = null;
if (File.Exists(pkgName))
{
//load file contents
sendBytes = File.ReadAllBytes(pkgName);
}
if (sendBytes != null)
{
networkStream.Write(sendBytes, 0, sendBytes.Length); //sendBytes.Length = 1001883;
networkStream.Flush();
}
...
Java Android code: client
InetAddress serverAddr = InetAddress.getByName(serverIp);
Log.d("SideloadManager", "C: Connecting...");
Socket socket = new Socket(serverAddr, serverPort);
InputStream inFromServer = socket.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
FileOutputStream outStream = new FileOutputStream("...\recieved.bmp");
int size = 1001883; //same size from server
byte[] buf = new byte[size];
in.read(buf);
outStream.write(buf, 0, buf.length);
outStream.flush();
outStream.close();
received.bmp is of same size as on server 1001883 bytes. But its contents gets corrupted. After debugging i have seen that:
on C# program byte array is [ 149, 145, 10, .....]
on Java program byte array is: [ -105, -101, 10, .....] this is due to signed byte in java
What am i missing to receive correct bitmap?
SOLVED as below:
Replace:
int size = 1001883; //same size from server
byte[] buf = new byte[size];
in.read(buf);
outStream.write(buf, 0, buf.length);
with this:
int len=-1;
byte[] buf = new byte[1024];
while ((len = in.read(buf, 0, buf.length)) > 0) {
outStream.write(buf, 0, len);
}
solved the issue :)
The data is transferred correctly because 149 and -105 have the same binary representation as bytes. The more likely problem is that you're not reading all of the data that was sent in the java side.
The read method returns the number of bytes that have been read, and -1 when the end of the stream has been reached. You need a loop to read the entire file:
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
outStream.write(buf, 0, bytesRead);
}
I wanted to create a project for streaming multiple images through net. I just wanted to start with small, functional code but already encountered a funky problem for me. Image is received, but it contains graphical bugs like its only a part of it.
Sadly cant show images cause of low rputation, here is link.
http://img543.imageshack.us/img543/1508/buggedy.jpg
Of course, million dollars for answer. ^^
TcpListener listener;
TcpClient client;
TcpClient datatoclient;
NetworkStream stream;
Host part:
listener = new TcpListener(5000);
listener.Start();
datatoclient = listener.AcceptTcpClient();
NetworkStream nowystream = datatoclient.GetStream();
MemoryStream ms = new MemoryStream();
byte[] image = File.ReadAllBytes("default.jpg");
switch (trackBar1.Value)
{
case 0:
image = File.ReadAllBytes("mirrion.jpg");
break;
case 1:
image = File.ReadAllBytes("tenis.jpg");
break;
case 2:
image = File.ReadAllBytes("marisasold.jpg");
break;
}
// get the image size in bytes
int numberOfBytes = image.Length;
// put the size into an array
byte[] numberOfBytesArray = BitConverter.GetBytes(numberOfBytes);
// send the image size
nowystream.Write(numberOfBytesArray, 0, numberOfBytesArray.Length);
// send the image
nowystream.Write(image, 0, numberOfBytes);
Client part:
client = new TcpClient("127.0.0.1", 5000);
stream = client.GetStream();
byte[] data = new byte[4];
// read the size
stream.Read(data, 0, data.Length);
int size = BitConverter.ToInt32(data, 0);
label1.Text = size.ToString();
// prepare buffer
data = new byte[size];
// load image
stream.Read(data, 0, data.Length);
// save image to file for test
File.WriteAllBytes("received.jpg", data);
MemoryStream MS = new MemoryStream(data);
pictureBox1.Image = Image.FromStream(MS);
stream.Read doesn't guarantee that it will read data.Length bytes. Instead it returns number of bytes read. So you should check its return value and continue reading till you get all the bytes.
See http://msdn.microsoft.com/en-us/library/system.io.stream.read(v=vs.90).aspx (Section Return Value)
Thr read method can be something like this
void Read(Stream stream, byte[] buffer,int offset,int len)
{
int read = 0;
while (read < len)
{
read += stream.Read(buffer, offset + read, len-read);
}
}
I have a problem with sending a screenshot via sockets in c#.
Client:
private void btnCaptureScreen_Click(object sender, EventArgs e)
{
clientSocket = new TcpClient();
clientSocket.Connect(txtIP.Text, 8888);
NetworkStream serverStream = clientSocket.GetStream();
byte[] inStream = new byte[9999999];
serverStream.Read(inStream, 0, (int)clientSocket.ReceiveBufferSize);
ImageConverter ic = new ImageConverter();
Image img = (Image)ic.ConvertFrom(inStream);
Bitmap bit = new Bitmap(img);
bit.Save(#"C:\temp\capturas\scn" + numCapturas + ".png", ImageFormat.Png);
clientSocket.Close();
}
server:
TcpListener serverSocket = new TcpListener(IPAddress.Parse(LocalIPAddress()), 8888);
TcpClient clientSocket = default(TcpClient);
serverSocket.Start();
NetworkStream networkStream = clientSocket.GetStream();
Bitmap bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
ImageConverter converter = new ImageConverter();
Byte[] sendBytes = (byte[])converter.ConvertTo(bmpScreenshot, typeof(byte[]));
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
this is a part of my code. If I save the screenshot in the server to a folder, it's working correctly, but after I send it via socket to the client, the client shows only the half of the image, the other half of the image is incorrect because it's all grey.
thanks!
EDIT: now i tryied to improve reading logic... but now doesn't work, a ArgumentException appears when i try to save the bitmap.
Client:
clientSocket = new TcpClient();
clientSocket.Connect(txtIP.Text, 8888);
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes("screenCapture()$");
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
byte[] bytesFrom = new byte[10025];
serverStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
String dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$"));
Int64 lengthdata = Convert.ToInt64(dataFromClient);
byte[] inStream = new byte[lengthdata];
int recived = 0;
while (recived != lengthdata)
{
recived += serverStream.Read(inStream, 0,(int)clientSocket.ReceiveBufferSize);
}
TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap));
Bitmap screenShot = (Bitmap)tc.ConvertFrom(inStream); //<--- Exception
screenShot.Save(#"C:\temp\capturas\scn" + numCapturas + ".png", ImageFormat.Png);
clientSocket.Close();
Server:
private void sendScreenCapture(NetworkStream networkStream)
{
Bitmap bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
ImageConverter converter = new ImageConverter();
byte[] sendBytes = (byte[])converter.ConvertTo(bmpScreenshot, typeof(byte[]));
byte[] tamañoImagen = System.Text.Encoding.ASCII.GetBytes(sendBytes.Length.ToString() + "$");
networkStream.Write(tamañoImagen, 0, tamañoImagen.Length);
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
}
EDIT 2: Haha finally i got it, i have to control the position in the byte[]:
int pos = 0;
while (lengthdata > 0)
{
int recived = serverStream.Read(inStream, pos, (int)lengthdata);
if (recived == 0) break;
lengthdata -= recived;
pos+=recived;
}
You're reading clientSocket.ReceiveBufferSize bytes once and stop. Presumably, the image is larger, so you're missing part of it. You'll need better reading logic...
Generally speaking, sound like you're trying to home-brew a remote desktop implementation - consider using actual Remote Desktop or similar tools.
I have problem with sending objects via TCPClient. At first, I serialize them into byte array and then I send them. TCPListener recieves some data, but deserializer is throwing exception "Unexpected end of stream".
Here is reciever code:
public void start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 8090);
listener.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
processClient(client);
}
}
public void processClient(TcpClient client)
{
NetworkStream net = client.GetStream();
ReadData(net);
byte[] response = Encoding.UTF8.GetBytes("Hello from the server.");
net.Write(response, 0, response.Length);
net.Close();
client.Close();
}
void ReadData(NetworkStream netstream)
{
byte[] buffer = new byte[2048];
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
netstream.ReadTimeout = 5000;
int bytes = -1;
while ((bytes = netstream.ReadByte()) != -1)
{
memStream.WriteByte((byte)bytes);
}
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bform = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
Packet packet = (Packet)bform.Deserialize(memStream);
OnMessageArrived(this, new MessageEventArgs(packet.From.ToString(), packet.Data.ToString()));
memStream.Close();
netstream.Close();
}
And here is sender code:
public void sendData(string to, Packet data)
{
TcpClient client = new TcpClient();
MemoryStream mstream = new MemoryStream();
client.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8090));
if (client.Connected)
{
NetworkStream stream = client.GetStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bform = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bform.Serialize(mstream, data);
byte[] buffer = new byte[2048];
mstream.Read(buffer, 0, buffer.Length);
stream.Write(buffer, 0, buffer.Length);
stream.Flush();
stream.Close();
client.Close();
}
}
Sender main method:
static void Main(string[] args)
{
SimplestTCPIP.Client client = new SimplestTCPIP.Client();
Packet packet = new Packet("client", "server", IPAddress.Parse("127.0.0.1"));
client.sendData("server", packet);
Console.WriteLine("IP: " + GetIP().ToString());
Console.Read();
}
Reciever main method:
static void Main(string[] args)
{
SimplestTCPIP.Server server = new SimplestTCPIP.Server();
server.OnMessageArrived += new SimplestTCPIP.Server.MessageArrived(server_OnMessageArrived);
Thread thread = new Thread(server.start);
thread.Start();
}
static void server_OnMessageArrived(object sender, SimplestTCPIP.Server.MessageEventArgs m)
{
Console.WriteLine(m.From + " : " + m.Text);
}
In your sendData method you serialize the object to a memory stream and then read it back into a buffer of 2048 bytes before writing it to the network stream. If the serialzed object is > 2048 bytes you would have a problem. I would try just serializing directly to the network stream or at least using the same kind of code as in your ReadData method where you write byte by byte.
Edit:
The size of the data is probably not the problem. You should still avoid the hard coded buffer size and stick with the code change you mention in the comment. Given your comment the problem lies elsewhere.
In both your sender and your receiver you write to a memory stream and then read from it. You can't do that unless you set the current position in the stream back to zero between the write and read.
So in your sendData method on the client add the line
mstream.Seek(0, SeekOrigin.Begin);
right after
bform.Serialize(mstream, data);
And in the ReadData method of your server add the line
memStream.Seek(0, SeekOrigin.Begin);
right before
Packet packet = (Packet)bform.Deserialize(memStream);
That way the memory stream is set to the beginning before you try and read from it.
I think you could just skip the memory stream all together and just read and write to the network stream, but you might have other reasons for it.