Transmitting file between C++ Client / C# Server over TCP - c#

I'm currently trying to send a stream of jpeg pictures between a c++ client and a C# server over TCP.
I'm using the transmitFile function on C++ side but I don't know if I'm handling it properly on C#-side.
I don't get runtime errors but the picture is not displayed, so I guess I'm missing something.
EDIT : Updated code, the fileSize I'm receiving is doing a stackOverflow...
C++ code (Client : sending picture)
void TCPclient::sendPicture(LPCWSTR filename, std::string filename_str)
{
HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
//Send file size
send(sock, (const char*)GetSize(filename_str), sizeof(int), 0);
LogManager::log(std::to_string(GetSize(filename_str)));
//Send file
TransmitFile(sock, hFile, GetFileSize(hFile, NULL), 1024, NULL, NULL, TF_USE_KERNEL_APC | TF_WRITE_BEHIND);
CloseHandle(hFile);
}
int TCPclient::GetSize(std::string filename)
{
struct stat stat_buf;
int rc = stat(filename.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}
C# code (Server : receiving the picture and displaying it)
while (true)
{
try
{
using (MemoryStream stream = new MemoryStream(ReceiveVarData(clientSock)))
{
stream.Position = 0;
Image image = Image.FromStream(stream);
if (image != null)
pictureBox1.Image = image;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public static byte[] ReceiveVarData(Socket s)
{
Console.WriteLine("Receiving data ...");
int offset = 0;
int recv;
Console.WriteLine("Receiving data size ...");
byte[] datasize = new byte[4];
s.Receive(datasize);
int size = BitConverter.ToInt32(datasize, 0);
Console.WriteLine("Data size " + size);
byte[] data = new byte[size];
while (offset < size)
{
Console.WriteLine("Downloading " + (offset/size)*100.0 + "%");
recv = s.Receive(data, offset, 1024, SocketFlags.None);
if (recv == 0)
{
data = null;
break;
}
offset += recv;
}
return data;
}

Change :
using (Image image = Image.FromStream(new MemoryStream(ReceiveVarData(clientSock))))
{
if (image != null)
pictureBox1.Image = image;
}
To this :
using ( MemoryStream stream = new MemoryStream(ReceiveVarData(clientSock)) )
{
stream.Position = 0;
Image image = Image.FromStream(stream);
if ( image != null )
pictureBox1.Image = image;
}
You're disposing your Image object right after creating it.
When instantiating MemoryStream with data buffer ( from what i remember ) will set it's position to the end of that stream so you have to set MemoryStream.Position back to the beginning.

Related

Transformation an image file in tcp/ip

I convert image file into a byte array and packetize it to 14-byte packets and send it via SerialPortEventHandler. on the other hand, in reciever part I lost some packets and when I generate recieved byte array in a new image file, the rest of the image, after the lost packet, shifted incorrectly, I have replaced lost packets with zero. while this works with text file perfectly. This is my code in client and server side:
client
_file = ofile.ConvertFileToByte(txtFileName.Text);
for (int k = 0; k < Configuration.PacketNumberInFrame; k++)
{
((BackgroundWorker)sender).ReportProgress((j * Configuration.PacketNumberInFrame + i) * 100 / Configuration.FileCount);
if (i + _numberOfByte <= Configuration.FileCount)
_packet = _file.SubArray(i, _numberOfByte);
}
//send packet
...
Server
try
{
while (true)
{
size = port.BytesToRead;
if (size >= 18)
break;
}
byte[] packet = new byte[size];
var str2 = port.Read(packet, 0, size);
if (System.Text.Encoding.Default.GetString(packet).Contains(Configuration.EndKeyByte) && !endFlag)
EndRecieving();
else
Extract(packet);
}
catch
(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public Extract(packet)
{
Recieve_Data.Add( packet);
}
public EndRecieving()
{
for(int i=0;i< arrayResult.AddRange(packetData);i++)
{
arrayResult.AddRange(packetData);
}
string filePath = Configuration.LogFilePath + "\\CreatedFile-" + "."filePrefix.ToLower();
var stream = new FileStream(filePath,
FileMode.Create,
FileAccess.ReadWrite);
FileData oFile = new FileData();
stream.Write(result, 0, result.Length);
stream.Close();
}

Sending Hex string to TCP Socket

I am connecting VideoJet Printer to my PC using TCP/IP, creating C# windows dekstop application to read and write TCP Socket. When I am semding below Hex String using hercules software [When HEX Checkbox tick] it is responding but when I am sending same hex string from my C# code it is not reponding
Please suggest me where I am doing wrong in my code
try
{
client = new TcpClient("192.168.2.1", Convert.ToInt32("3001"));
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = HexString2Bytes(richTextBox3.Text);
stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent: {0}",richTextBox3.Text);
// Receive the TcpServer.response.
data = new Byte[65000];
var readStream = new MemoryStream();
int readBytes = stream.Read(data, 0, data.Length);
while (readBytes > 0)
{
readStream.Write(data, 0, readBytes);
readBytes = stream.Read(data, 0, data.Length);
}
var responseData = Encoding.ASCII.GetString(readStream.ToArray());
}
catch (Exception ex)
{
string errormsg = ex.ToString();
}
private byte[] HexString2Bytes(string hexString)
{
//check for null
if (hexString == null) return null;
//get length
int len = hexString.Length;
if (len % 2 == 1) return null;
int len_half = len / 2;
//create a byte array
byte[] bs = new byte[len_half];
try
{
//convert the hexstring to bytes
for (int i = 0; i != len_half; i++)
{
bs[i] = (byte)Int32.Parse(hexString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
}
}
catch (Exception ex)
{
MessageBox.Show("Exception : " + ex.Message);
}
//return the byte array
return bs;
}
Command Hex String
A503CA002C000000E4411251C0000000B60000003C0050006100720061006D0073003E00200020003C0043006F006C002000690064003D00220044006500760069006300650073002F0050004800640073002F0031002F005000720069006E00740049006E0066006F0072006D006100740069006F006E002200200067006500740046006C006100670073003D002200320022002000670065007400440065007000740068003D0022002D003100220020002F003E003C002F0050006100720061006D0073003E000000
I actually don't know, why you have to make a While loop. when you received number of bytes from Server readBytes, so you could finish a code with Encoding like this:
string responseData = Encoding.ASCII.GetString(data,0,readbytes);
To get more information, you can find in this link https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient?view=net-5.0

System.Drawing.Image Parameter Not Valid

I know this has been asked numerous times... and I have searched and tried everything that I can, but I am still not sure why I get the "parameter is not valid" exception...
I have an Amazon EC2 instance running Windows Server 2012. On that machine, I am running Unity3D (Unity 5). That Unity application is sending frames (images) from the EC2 instance to my local laptop, via TCP. My client is running Windows 10, not that it is likely to make any difference.
To get my image data, I do the following:
byte[] GetScreenData() {
// Create a texture the size of the screen, RGB24 format
int width = Screen.width;
int height = Screen.height;
RenderTexture rt = new RenderTexture(width, height, 24);
Texture2D tex = new Texture2D(width, height, TextureFormat.RGB24, false);
Camera camera = GameObject.Find("Main Camera").GetComponent < Camera > ();
camera.targetTexture = rt;
camera.Render();
RenderTexture.active = rt;
// Read screen contents into the texture
tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
camera.targetTexture = null;
RenderTexture.active = null;
Destroy(rt);
// Encode texture into JPG
byte[] bytes = tex.EncodeToJPG();
Destroy(tex);
return bytes;
}
I then serialize my data using FlatBuffers:
public static byte[] FlatSerialize(this ServerToClientMessage message) {
var builder = new FlatBufferBuilder(1);
//Create an ID
var MessageId = builder.CreateString(message.MessageId.ToString());
//Start the vector...
//Loop over each byte and add it - my god, is there not a better way?
FlatServerToClientMessage.StartImagebytesVector(builder, message.ImageBytes.Length);
foreach(var imageByte in message.ImageBytes) {
builder.AddByte(imageByte);
}
var imagebytes = builder.EndVector();
//Start the FlatServerToClientMessage and add the MessageId and imagebytes
FlatServerToClientMessage.StartFlatServerToClientMessage(builder);
FlatServerToClientMessage.AddMessageid(builder, MessageId);
FlatServerToClientMessage.AddImagebytes(builder, imagebytes);
//End the FlatServerToClientMessage and finish it...
var flatMessage = FlatServerToClientMessage.EndFlatServerToClientMessage(builder);
FlatServerToClientMessage.FinishFlatServerToClientMessageBuffer(builder, flatMessage);
return builder.SizedByteArray();
}
Next, I send my data:
public void SendRaw(byte[] dataToSend) {
///We must send the length of the message before sending the actual message
var sizeInfo = new byte[4]; // = BitConverter.GetBytes(dataToSend.Length);
//Shift the bytes
sizeInfo[0] = (byte) dataToSend.Length;
sizeInfo[1] = (byte)(dataToSend.Length >> 8);
sizeInfo[2] = (byte)(dataToSend.Length >> 16);
sizeInfo[3] = (byte)(dataToSend.Length >> 24);
try {
var stream = Client.GetStream();
//Send the length of the data
stream.Write(sizeInfo, 0, 4);
//Send the data
stream.Write(dataToSend, 0, dataToSend.Length);
} catch (Exception ex) {
Debug.LogException(ex);
} finally {
//raise event to tell system that the client has disconnected and that listening must restart...
}
}
Back on my client device, I am listening for incoming data which deserializes and raises an event to alert the system to the arrival of a new image...
private void Run() {
try {
// ShutdownEvent is a ManualResetEvent signaled by
// Client when its time to close the socket.
while (!ShutDownEvent.WaitOne(0)) {
try {
if (!_stream.DataAvailable) continue;
//Read the first 4 bytes which represent the size of the message, and convert from byte array to int32
var sizeinfo = new byte[4];
_stream.Read(sizeinfo, 0, 4);
var messageSize = BitConverter.ToInt32(sizeinfo, 0);
//create a new buffer for the data to be read
var buffer = new byte[messageSize];
var read = 0;
//Continue reading from the stream until we have read all bytes #messageSize
while (read != messageSize) {
read += _stream.Read(buffer, read, buffer.Length - read);
}
var message = new ServerToClientMessage().FlatDeserialize(buffer);
//raise data received event
OnDataReceived(message);
} catch (IOException ex) {
// Handle the exception...
}
}
} catch (Exception ex) {
// Handle the exception...
} finally {
_stream.Close();
}
}
To deserialize, I do the following:
public static ServerToClientMessage FlatDeserialize(this ServerToClientMessage message, byte[] bytes) {
var bb = new ByteBuffer(bytes);
var flatmessage = FlatServerToClientMessage.GetRootAsFlatServerToClientMessage(bb);
message.MessageId = new Guid(flatmessage.Messageid);
message.ImageBytes = new byte[flatmessage.ImagebytesLength];
for (var i = 0; i < flatmessage.ImagebytesLength; i++) {
message.ImageBytes[i] = flatmessage.GetImagebytes(i);
}
return message;
}
For clarity, here is the ServerToClientMessage class:
public class ServerToClientMessage : EventArgs
{
public Guid MessageId { get; set; }
public byte[] ImageBytes { get; set; }
}
Anyway, next, the OnDataReceived event gets raised and that in turn calls a function to convert from the ImageBytes array to a System.Drawing.Image. That function is here:
public Image byteArrayToImage(byte[] byteArrayIn) {
// SAME PROBLEM!
//var converter = new System.Drawing.ImageConverter();
// return (Image)converter.ConvertFrom(byteArrayIn); ;
using(var memoryStream = new MemoryStream(byteArrayIn)) {
return Image.FromStream(memoryStream, false, false);
}
}
Now, my image data being sent from the server is fine and dandy... I have validated it. This all works fine when I use JSON, too. I've tried many ways to convert from a byte array to an Image, but I always seem to get the Parameter is not valid exception. I've also tried sending my image in different formats like JPG and PNG, as well as raw pixel data.
Anyone have an idea?
Figured it out.
It turns out that the data is backwards...due to FlatBuffers serialization.
The solution is to reverse the order of my for-loop during serialization:
for (var i = message.ImageBytes.Length; i -->0;)
{
builder.AddByte(message.ImageBytes[i]);
}

How can I make each flush() work, which make each buffer sent before next write() in C#

I am trying to sent very screenshot when i move the mouse on the screen. Therefore, I will sent the size of screenshot and image byte[]. In my client side, I will set the size byte array by the size received from server, and read the rest of byte[] as image. Ideally, I need each time I call the write(), the byte[] I want write into should be empty, so I use the flush(). In fact, after I received the getinputstream(), Sometime I will get the old data inside it. I don't know why flush() doesn't work. anyone has better ideas to solve this problem?
This is my code for server, I try use stream, and networkstream, it dosent works.
public void send(byte[] imageByte)
{
Stream stream = client.GetStream();
client.NoDelay = true;
client.Client.NoDelay = true;
Debug.WriteLine("noDelay:{0}, client.noDelay:{1}", client.NoDelay, client.Client.NoDelay);
byte[] imageSize;
string imgSize = Convert.ToString(imageByte.Length);
Debug.WriteLine("string=" + imgSize);
imageSize = Encoding.ASCII.GetBytes(imgSize);
Debug.WriteLine(" header size:" + imageSize.Length);
//ns.Write(imageSize, 0, imageSize.Length);
//ns.Flush();
//sleep 500 ms
stream.Write(imageSize, 0, imageSize.Length);
stream.Flush();
Thread.Sleep(150);
Debug.WriteLine("sent size");
//ns.Write(imageByte, 0, imageByte.Length);
//ns.Flush();
stream.Write(imageByte, 0, imageByte.Length);
stream.Flush();
Debug.WriteLine("First time sent image size:" + imageByte.Length);
client side:
public class connection extends AsyncTask {
private byte[] data;
public void setByteSize(int size) {
data = new byte[size];
}
public byte[] getByteSize() {
return data;
}
#Override
protected Object doInBackground(Object... arg0) {
try {
clientSocket = new Socket("134.129.125.126", 8080);
// clientSocket = new Socket("134.129.125.172", 8080);
System.out.println("client connect to server");
input = clientSocket.getInputStream();
System.out.println("getinputstream");
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (true) {
int totalBytesRead = 0;
int chunkSize = 0;
int tempRead = 0;
String msg = null;
// byte[] data = null;
byte[] tempByte = new byte[1024 * 1024 * 4];
try {
// read from the inputstream
tempRead = input.read(tempByte);
// tempbyte has x+5 byte
System.out.println("Fist time read:" + tempRead);
// convert x+5 byte into String
String message = new String(tempByte, 0, tempRead);
msg = message.substring(0, 5);
int msgSize = Integer.parseInt(msg);
data = new byte[msgSize];
// for(int i =0;i<tempRead-5;i++)
// {
// data[i]=tempByte[i+5];
// }
for (int i = 0; i < msgSize; i++) {
data[i] = tempByte[i + 5];
}
// cut the header into imageMsg
// String imageMsg = new String(tempByte, 5, tempRead - 5);
// convert string into byte
System.out.println("message head:" + msg);
byteSize = Integer.parseInt(msg);
System.out.println("ByteSize:" + byteSize);
// convert String into byte[]
totalBytesRead = tempRead - 5;
System.out.println("total Byte Read=" + totalBytesRead);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// get string for the size of image
try {
while (totalBytesRead != getByteSize().length) {
System.out.println("data length:"
+ getByteSize().length);
chunkSize = input.read(getByteSize(), totalBytesRead,
getByteSize().length - totalBytesRead);
System.out.println("chunkSize is " + chunkSize);
totalBytesRead += chunkSize;
// System.out.println("Total byte read "
// + totalBytesRead);
}
System.out.println("Complete reading - total read = "
+ totalBytesRead);
} catch (Exception e) {
}
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
System.out.println("deco");
runOnUiThread(new Runnable() {
public void run() {
image.setImageBitmap(bitmap);
System.out.println("setImage at less than 500");
}
});
}
}
}

Base64 from e.ChosenPhoto apparently corrupted

//convert photo to baos
var memoryStream = new System.IO.MemoryStream();
e.ChosenPhoto.CopyTo(memoryStream);
//string baos = memoryStream.ToString();
byte[] result = memoryStream.ToArray();
String base64 = System.Convert.ToBase64String(result);
String post_data = "&image=" + base64;
...
wc.UploadStringAsync(imgur_api,"POST",post_data);
I am using this code to upload an image to the Imgur API v3 using WebClient. The image being selected is either one of the 7 photos provided by the Windows Phone 7.1 emulator, or the simulated camera images. When I try to load the images, they are a largely-grey corrupted mess. Am I generating the base64 properly and/or do I need to render a Bitmap of the picture first before creating the byte[] and base64?
Thanks in advance!
Use something like Uri.EscapeDataString to escape the data so that special URL characters are not interpreted.
I use this
private void PhotoChooserTaskCompleted(object sender, PhotoResult e)
{
if (e.TaskResult != TaskResult.OK) return;
var bimg = new BitmapImage();
bimg.SetSource(e.ChosenPhoto);
var sbytedata = ReadToEnd(e.ChosenPhoto);
}
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = stream.Position;
stream.Position = 0;
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
stream.Position = originalPosition;
}
}
And upload byte[] to server. Hope it's help

Categories