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.
Related
I try to get a connection between an UWP-programm and a "normal" C# application.
UWP:
StreamSocket s = new StreamSocket();
await socket.ConnectAsync(new HostName("localhost"), "8003");
BinaryWriter bw = new BinaryWriter(socket.OutputStream.AsStreamForWrite());
String toSend = "Hello World!";
byte[] text = Encoding.UTF8.GetBytes(toSend);
byte[] number = BitConverter.getBytes(text.Length);
if(BitConverter.isLittleEndian) Array.Reverse(number);
bw.Write(number, 0, number.Length);
bw.Write(text, 0, text.Length);
"normal" C#, after the TcpListener etablished a new ClientThread:
//client was accepted by the server and is an instance of TcpClient
BinaryReader br = new BinaryReader(client.GetStream());
byte[] number = new byte[4];
br.Read(number, 0, number.Length);
if(BitConverter.isLittleEndian) Array.Reverse(number);
int size = BitConverter.ToInt32(number);
byte[] buffer = new byte[size];
br.Read(buffer, 0, buffer.Length);
String recieved = Encoding.UTF8.GetString(buffer);
Debug.WriteLine(recieved);
But the server doesn´t recieves anything. And the int size is 0. But if i run the UWP-code on a "normal" C# application, by replacing the s.OutputStream.AsStreamForWrite() with client.GetStream() and using a TcpClient instead of an StreamSocket the server recieves the text. What am I doing wrong?
Greets Marcel
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:
I just wonder how to read Response code from TCP client? The sample codes are below.
var tcpClient = new TcpClient();
tcpClient.Connect(this.Settings.MailServer, this.Settings.MailServerPort);
NetworkStream stream = tcpClient.GetStream();
Stream > byte > String
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
response = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine(response);
You could use this:
byte[] message = new byte[512];
int bytesRead;
bytesRead = stream.Read(message, 0, message.Length);
ASCIIEncoding encoder = new ASCIIEncoding();
Console.WriteLine(encoder.GetString(message, 0, bytesRead));
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 wrote this code which sends an Image between sender and receiver.
First you must run receiver then run sender.
When I test this code on images between 1KB and 1.5KB, it works fine, but when I try to send a larger image, this message appears
cannot evaluate expression because a
native ..........
My code is below, can someone help?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Threading;
namespace UPDTester
{
public class UDPClass
{
public Image Merge(Queue<byte[]> myList)
{
int ImgHeight = BitConverter.ToInt32(myList.Dequeue(), 0);
int ImgWidth = BitConverter.ToInt32(myList.Dequeue(), 0);
Bitmap bmp = new Bitmap(ImgWidth, ImgHeight);
Graphics g = Graphics.FromImage(bmp);
int x, y = 0;
while (myList.Count > 0)
{
x = BitConverter.ToInt32(myList.Dequeue(), 0);
y = BitConverter.ToInt32(myList.Dequeue(), 0);
g.DrawImage(ByteToBitmapConverter(myList.Dequeue()), x, y);
}
return bmp;
}
/// <summary>
/// Image Segmentatoin.
/// img: the image that we like to divided.
/// </summary>
public Queue<byte[]> Segmentation(Bitmap img)
{
Queue<byte[]> ByteArray = new Queue<byte[]>();
ByteArray.Enqueue(BitConverter.GetBytes(img.Width));
ByteArray.Enqueue(BitConverter.GetBytes(img.Height));
Image temimg;
for (ushort x = 0; x < img.Width - 5; x += 5)
{
for (ushort y = 0; y < img.Height - 5; y += 5)
{
//temimg = null;
temimg = img.Clone(new Rectangle(x, y, 5, 5), PixelFormat.Format32bppArgb);
ByteArray.Enqueue(BitConverter.GetBytes(x));
ByteArray.Enqueue(BitConverter.GetBytes(y));
ByteArray.Enqueue(ImageToByteConverter(temimg));
}
}
return ByteArray;
}
//Sender
public void SenderUDP(Bitmap img)
{
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
string welcome = "Hello, are you there?";
data = Encoding.ASCII.GetBytes(welcome);
server.SendTo(data, data.Length, SocketFlags.None, ipep);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)sender;
data = new byte[1024];
int recv = server.ReceiveFrom(data, ref Remote);
MessageBox.Show("Message received from");
MessageBox.Show(Encoding.ASCII.GetString(data, 0, recv));
Queue<byte[]> temlist = Segmentation(img);
data = new byte[1024];
data =temlist.Dequeue();
//Send Width of image.
server.SendTo(data, data.Length, SocketFlags.None, ipep);
data = new byte[1024];
data = temlist.Dequeue();
//Send Height of image.
server.SendTo(data, data.Length, SocketFlags.None, ipep);
data = BitConverter.GetBytes(temlist.Count);
//Send Count of all list.
server.SendTo(data, data.Length, SocketFlags.None, ipep);
MessageBox.Show(temlist.Count.ToString() + " Iam Sender");
while (temlist.Count > 0)
{
server.SendTo(temlist.Dequeue(), Remote);
//MessageBox.Show(temlist.Count.ToString() + "S");
}
//server.Close();
}
//Receiver..(IP, PortNum)
public Image ReceiverUDP()
//public void ReceiverUDP(ref PictureBox pic)
{
int recv;
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
newsock.Bind(ipep);
MessageBox.Show("Waiting for a client....");
//Console.WriteLine("Waiting for a client....");
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);
recv = newsock.ReceiveFrom(data, ref Remote);
MessageBox.Show("Message received from ", Remote.ToString());
MessageBox.Show(Encoding.ASCII.GetString(data, 0, recv));
//Console.WriteLine("Message received from {0}:", Remote.ToString());
//Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
string welcome = "Welcome to my test server";
data = Encoding.ASCII.GetBytes(welcome);
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
Queue<byte[]> TempList = new Queue<byte[]>();
//Receive Width of image.
newsock.ReceiveFrom(data, ref Remote);
TempList.Enqueue(data);
//Receive Height of image.
newsock.ReceiveFrom(data, ref Remote);
TempList.Enqueue(data);
//reccive Count of the list.
newsock.ReceiveFrom(data, ref Remote);
int count = BitConverter.ToInt32(data, 0);
MessageBox.Show(count.ToString() + " Iam Receiver");
data = new byte[1024];
while (count > 0)
{
data = new byte[1024];
newsock.ReceiveFrom(data, ref Remote);
TempList.Enqueue(data);
data = new byte[1024];
newsock.ReceiveFrom(data, ref Remote);
TempList.Enqueue(data);
data = new byte[1024];
newsock.ReceiveFrom(data, ref Remote);
TempList.Enqueue(data);
MessageBox.Show(count.ToString());
count -= 3;
}
return Merge(TempList);
}
private byte[] ImageToByteConverter(Image img)
{
MemoryStream ms = new MemoryStream();
img.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
private Image ByteToBitmapConverter(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer);
Image img = Image.FromStream(ms);
return img;
}
}
}
Most likely the reason it locks up is because UDP doesn't guarantee delivery. Packets can be dropped. If that happens, your receive loop is going to sit there waiting forever for a packet that won't ever come.