using python to send an image over TCP to c# server - c#

I am working on a project that uses a python script to send an image taken with a webcam to a c# webserver using sockets. I am currently sending strings to the server from the python client using code like:
info = bytearray("Text to send", "UTF-8")
socket.send(info)
to send data to the c# server and it functions perfectly for text and numbers. I run into an issue when trying to encode the data read from the .bmp into "UTF-8", as trying this returns an error of not being able to encode certain characters into UTF-8.
I was wondering if anyone had any idea of a way to encode this that c# will be able to recognize, or, if there is a better way of trying to implement this process, I am all ears.
A couple of options I have come up with would be to 1 - use something like google drive to save the image to, or an FTP server and then have the c# server retrieve it from there or 2 - create a packet system containing the RGB values and recreating the image from those pixel values on the server.
Thanks for your help.
EDIT: I have tried sending the file this way
data = bytearray("123456789","UTF-8")
file = open("image.bmp", "rb")
data += file.read()
socket.send(data)
and was able to successfully retreive the string "123456789", but the data after this is garbage. I have also implemented sending the size of the file before sending the data and that size number is retrieved fine, but the img data saves as a black bmp.
Edit 2 :
Here is the server and client code I am using to try and recreate the image using a memory stream. I the client code is using the process mentioned by hcalves.
Client
if __name__ == "__main__":
sock = socket.socket()
sock.connect(("localhost", 50839))
with open("image.bmp", "rb") as fd:
buf = fd.read(1024)
while (buf):
sock.send(buf)
buf = fd.read(1024)
sock.close()
Server
Socket client = server.AcceptSocket();
NetworkStream stream = new NetworkStream(client);
byte[] imgData = new byte[1024];
MemoryStream memstream = new MemoryStream();
stream.Read(imgData,0, 1024);
int counter = 0;
while (stream.DataAvailable)
{
memstream.Write(imgData, 0, 1024);
stream.Read(imgData, 0, 1024);
counter = counter + 1024;
}
memstream.Seek(0, SeekOrigin.Begin);
using (Stream file = File.OpenWrite("img.bmp"))
{
byte[] buffer = new byte[8*1024];
int len;
while ((len = memstream.Read(buffer, 0, buffer.Length)) > 0)
{
file.Write(buffer,0,len);
}
}

You shouldn't need more than this recipe:
import socket
if __name__ == "__main__":
sock = socket.socket()
sock.connect(("localhost", 50839))
with open("data.bin", "rb") as fd:
buf = fd.read(1024)
while (buf):
sock.send(buf)
buf = fd.read(1024)
sock.close()
For practical reasons, you can treat str objects (the result of fd.read) as raw data, you don't need any further crazy encoding. Just iterate the file and send over the socket. Test by running this server which just echoes to stdout with python server.py > data2.bin:
import socket
import sys
if __name__ == "__main__":
sock = socket.socket()
sock.bind(("localhost", 50839))
sock.listen(1)
client, address = sock.accept()
buf = client.recv(1024)
while (buf):
sys.stdout.write(buf)
buf = client.recv(1024)
client.close()
sock.close()
A checksum shows the binary data is sent correctly:
% md5 data.bin data2.bin
MD5 (data.bin) = 8b3280072275badf3e53a6f7aae0b8be
MD5 (data2.bin) = 8b3280072275badf3e53a6f7aae0b8be
Your C# server should be able to accept this data as is. If it doesn't work, it's because your server is expecting something in particular, not just raw data.

Related

Images streamed over tcp are split in 3 with middle missing

The goal of the project is to stream video captured from a python host to a c# client via tcp sockets.
Relavent python2 server script:
import cv2
import numpy as np
import socket
from threading import Thread
_continue = True
def imageStreamer4():
global _continue
cam = cv2.VideoCapture(0)
camSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
camSocket.bind(("",8081))
camSocket.listen(1)
# set flip image to false if you don't want the image to be flipped
flipImage = True
while _continue:
try:
client,address = camSocket.accept()
print("client connected")
ret,camImage = cam.read()
if flipImage:
camImage = cv2.flip(camImage,1)
#uncomment the below code to view the webcam stream locally
"""
cv2.imshow('image',camImage)
if cv2.waitKey(1) == 27:
break # esc to quit
"""
byteString = bytes(cv2.imencode('.jpg', camImage)[1].tostring())
fileSize = len(byteString)
totalSent = 0
client.send(str(fileSize).encode())
sizeConfirmation = client.recv(1024)
totalSent = 0
while totalSent < fileSize:
totalSent += client.send(byteString[totalSent:])
print(str(fileSize), str(totalSent),sizeConfirmation.decode('utf-8'))
except Exception as e:
print(e)
print("shutting down video stream")
_continue = False
print("video stream exited.")
Relevant c# client code:
using System.Collections;
using UnityEngine;
using System;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using UnityEngine.UI;
using System.IO;
void getVideoStream()
{
byte[] header;
int recieved;
int fileSize;
NetworkStream dataStream;
MemoryStream ms;
while (connectCam)
{
fileSize = 0;
recieved = 0;
camClient = new TcpClient(camIP, camPort);
//get header
dataStream = camClient.GetStream();
while (!dataStream.DataAvailable)
{
//waste time
}
header = new byte[1024];
dataStream.Read(header, 0, header.Length);
fileSize = Int32.Parse(Encoding.Default.GetString(bytesReducer(header)));
byte[] result = Encoding.ASCII.GetBytes(fileSize.ToString());
//send response
dataStream.Write(result, 0, result.Length);
ms = new MemoryStream();
while (!dataStream.DataAvailable)
{
//waste time
}
while (recieved < fileSize)
{
byte[] data = new byte[camClient.ReceiveBufferSize];
recieved += dataStream.Read(data, 0, data.Length);
ms.Write(data, 0, data.Length);
}
//the below class simply sends function calls from secondary thread back to the main thread
UnityMainThreadDispatcher.Instance().Enqueue(convertBytesToTexture(ms.ToArray()));
dataStream.Close();
camClient.Close();
}
}
void convertBytesToTexture(byte[] byteArray) {
try
{
camTexture.LoadImage(byteArray); //Texture2D object
camImage.texture = camTexture; //RawImage object
}
catch (Exception e)
{
print(e);
}
}
The byte counts sent and received match as they should. I'm admittedly new to working with sockets but I'm pretty certain that the data is arriving whole and intact. Unfortunately I really have no idea why the image is splitting as it is. (As shown in the above image) If it's relevant at all, both the server and client functions are being run on their own separate threads.
I've run the scripts on separate hosts and clients and the results remain the same.If any different information is required to help, just ask. I'll be happy to update as required.
I was able to bring the picture together properly by removing empty space inserted by the following code:
while (recieved < fileSize)
{
byte[] data = new byte[camClient.ReceiveBufferSize];
recieved += dataStream.Read(data, 0, data.Length);
ms.Write(data, 0, data.Length);
}
replacing it with this:
int increment = 0;
while (recieved < fileSize)
{
byte[] data = new byte[camClient.ReceiveBufferSize];
increment = dataStream.Read(data, 0, data.Length);
recieved += increment;
ms.Write(data.Take(increment).ToArray(), 0, increment);
}
So instead of taking an array the size of the client's buffer into the memory stream(even if it wasn't full), it's being condensed to only the amount of information received via the read method. This effectively removed all the blank space in the received image.
Because Tcp is a stream you should consider it as a flow of bytes so you should apply some mechanism to identify each image
this way you can apply:
A delimiter:
use a set of bytes to separate each image( but this byte set must not repeated in your stream) for example:
1- send image bytes
2-send delimiter
in the client you start to read until reach the delimiter
Consider defining a protocol and send the image size first and then send image data for example :
1-first 8 bytes is always image size
2- then the image bytes
and when you read data on the client first you always read 8 bytes and then base on this size you read the rest of data.
Another way is to use fixed size data(which is a bit hard for you in this case) you get a fix size byte array in the server and if the image data is less than the byte array fill it with zero and on the client always read bytes as many as the server array size.
Server Send byte[2048] and Client reads until the bytes which is readed reach 2048

c# tcp programming a simple way to transfer binary file from client to server

I am doing my project about TCP server and client, so this project I want to transfer a binary file like:
.exe
.jpg
.docx
.txt
.dll
and etc..
I already try so many different ways in my code to transfer the file and still failed.
Problem I got when using this code, transfer file more then size of 9kb:
byte[] ba = File.ReadAllBytes(filename);
Everything fine because I read all bytes inside the file
After that I sent it to server using:
stm.Write(ba, 0, ba.Length);
Client successfully sent the data to server
On server the code is like this to receive the file data from client:
recv = "";
byte[] bb = new byte[8000000];
int k = control.Receive(bb);
for (int i = 0; i < k; i++)
recv += Convert.ToChar(bb[i]);
rec = Convert.ToString(recv);
byte[] array = Encoding.ASCII.GetBytes(rec);
File.WriteAllBytes(filename, array);
MessageBox.Show("download success!");
So server successfully receive the data from client and server encode it
to byte array and save the data into file using this:
File.WriteAllBytes(filename, array);
The problem is
The file that I sent was more then 9 kb size
When server write the data in file it just corrupt the file
and the size file not same as exactly the actual file size from client
So what the problem I have here? And how to solve it?
If python its easy to get big data using timeout like this code:
import socket
import os
import sys
from thread import *
import time
import random
def recv_timeout(socket,timesz):
socket.setblocking(0)
total_data=[]
data=""
begin=time.time()
while 1:
if total_data and time.time()-begin >timesz:
break
elif time.time()-begin > timesz*2:
break
try:
data = socket.recv(8192)
if data:
total_data.append(data)
begin=time.time()
else:
time.sleep(0.1)
except:
pass
return ''.join(total_data)
I use this code to receive big data and its successful receive a jpg file.. is it possible to use this method from python on C#?
You do not need encode all bytes to string. Try this code:
var chunkSize = 8000000;
byte[] bb = new byte[chunkSize];
using (var file = File.OpenWrite(filename))
{
while (true)
{
var bytesReceived = control.Receive(bb);
file.Write(bb, 0, bytesReceived);
if (bytesReceived < chunkSize)
break;
}
}
MessageBox.Show("download success!");
For your python code, there is no need in reading unblocking and doing the blocking yourself. All the waiting and timeout mechanisms are builtin to your socket:
def recv_all(socket):
total_data = []
while True:
data = socket.recv(8192)
if not data:
break
total_data.append(data)
return ''.join(total_data)
You have to do the same in your C#-code: receive data until the socket on the sending side is closed.
recv = "";
int k;
do {
byte[] bb = new byte[8000];
k = control.Receive(bb);
for (int i = 0; i < k; i++)
recv += Convert.ToChar(bb[i]);
} while(k);

Sending large image through TCPClient c#

I have the following code to send a picture to a receiving application
public static void sendFile(string file, string ip)
{
using (TcpClient client = new TcpClient())
{
client.Connect(IPAddress.Parse(ip), 44451);
//Console.WriteLine(ip);
NetworkStream nwStream = client.GetStream();
MemoryStream ms = new MemoryStream();
Image x = Image.FromFile(file);
x.Save(ms, x.RawFormat);
byte[] bytesToSend = ms.ToArray();
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
nwStream.Flush();
client.Close();
}
}
and I'm receiving the file on the other end with this
NetworkStream nwStream = clientCopy.GetStream();
byte[] buffer = new byte[clientCopy.ReceiveBufferSize];
//---read incoming stream---
int bytesRead = nwStream.Read(buffer, 0, clientCopy.ReceiveBufferSize);
MemoryStream ms = new MemoryStream(buffer);
Image returnImage = Image.FromStream(ms);
//ms.Flush();
//ms.Close();
String path;
if (!Directory.Exists(path = #"C:\Users\acer\AppData\Roaming\test"))
{
Directory.CreateDirectory(#"C:\Users\acer\AppData\Roaming\test");
}
string format;
if (ImageFormat.Jpeg.Equals(returnImage.RawFormat))
{
format = ".jpg";
}
else if (ImageFormat.Png.Equals(returnImage.RawFormat))
{
format = ".png";
}
else
{
format = ".jpg";
}
returnImage.Save(#"C:\Users\acer\AppData\Roaming\test\default_pic" + format, returnImage.RawFormat);
If i'm sending a picture that is small (around <20kb) the file is received 100% on the other end but if I send a file around >=100kb, the picture is received but only half of the image is loaded. I'm aware of the approach of reading the stream until all data is read but I don't know how to implement it right.
Thank you
You're only calling Read once, which certainly isn't guaranteed to read all the bytes. You could either loop, calling Read and copying the relevant number of bytes on each iteration, or you could use Stream.CopyTo:
var imageStream = new MemoryStream();
nwStream.CopyTo(imageStream);
// Rewind so that anything reading the data will read from the start
imageStream.Position = 0;
... or you could just read the image straight from the network stream:
// No need for another stream...
Image returnImage = Image.FromStream(nwStream);
(It's possible that would fail due to the stream being non-seekable... in which case using CopyTo as above would be the simplest option.)
The TCP protocol (like any other stream protocol) can't be used to transfer data as is. Most of the time it is impossible to know whether all data is arrived or whether it is received unrelated chunk of data together with the expected one. Therefore it is almost always needed to define underlying protocol, for example by sending a message header (like in HTTP) or defining a message separator (like line break in Telnet; however, using separators for big size messages are impractical). In most simple case it is enough to define very simple header that contains only the length of the message
Thus, in your case you can send 4 byte image length and then the image. On the server side you will read the 4 bytes size and then in the loop call the Read until complete message is recieved.
Please note that you can receive more bytes than expected. It means that the last chunk contains the beginning of the next message.

How to read the content of file from port

I am in needed to use the text data in to a program when someone prints a file.
I have basic ideas about the TCP/IP client and listener programming.
Already I could send and receive txt files between two machines.
But how to receive the file contents if the files were in docx,xlx,pdf or any other format?
My requirement is,
I wanted to use the contents (texts) of a file in to another program when someone prints a file.
Please suggest me if there is some alternative ways to do it.
Thank in advance.
Since you haven't posted any code I'll write the code part in "my way" but you should have a bit of understanding after reading this.
First on both of the ends ( client and server ) you should apply unified protocol which will describe what data you're sending. Example could be:
[3Bytes - ASCII extension][4Bytes - lengthOfTheFile][XBytes - fileContents]
Then in your sender you can receive data according to the protocol which means first your read 3 bytes to decide what format file has, then you read 4 bytes which will basically inform you how large file is incomming. Lastly you have to read the content and write it directly to the file. Example sender could look like this :
byte[] extensionBuffer = new byte[3];
if( 3 != networkStream.Read(extensionBuffer, 0, 3))
return;
string extension = Encoding.ASCII.GetString(extensionBuffer);
byte[] lengthBuffer = new byte[sizeof(int)];
if(sizeof(int) != networkStream.Read(lengthBuffer, 0, 3))
return;
int length = BitConverter.ToInt32(lengthBuffer, 0);
int recv = 0;
using (FileStream stream = File.Create(nameOfTheFile + "." + extension))
{
byte #byte = 0x00;
while( (#byte = (byte)networkStream.ReadByte() ) != 0x00)
{
stream.WriteByte(#byte);
recv++;
}
stream.Flush();
}
On the sender part you can read the file extension then open up the file stream get the length of the stream then send the stream length to the client and "redirect" each byte from FileStream into a networkStream. This can look something like :
FileInfo meFile = //.. get the file
byte[] extBytes = Encoding.ASCII.GetBytes(meFile.Extension);
using(FileStream stream = meFile.OpenRead())
{
networkStream.Write(extBytes, 0, extBytes.Length);
networkStream.Write(BitConverter.GetBytes(stream.BaseStream.Length));
byte #byte = 0x00;
while ( stream.Position < stream.BaseStream.Length )
{
networkStream.WriteByte((byte)stream.ReadByte());
}
}
This approach is fairly easy to implement and doesn't require big changes if you want to send different file types. It lack some validator but I think you do not require this functionality.

How to read unknown data length in a TCP Client

I am relativity new to C#. In my TCP client have the following function which sends data to the server and returns the response:
private static TcpClient tcpint = new TcpClient(); //Already initiated and set up
private static NetworkStream stm; //Already initiated and set up
private static String send(String data)
{
//Send data to the server
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(data);
stm.Write(ba, 0, ba.Length);
//Read data from the server
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
//Construct the response from byte array to string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < k; i++)
{
sb.Append(bb[i].ToString());
}
//Return server response
return sb.ToString();
}
As you can see here, when I am reading the response from the server, I am reading it into a fix byte[] array of length 100 bytes.
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
What do i do if the response from the server is more than 100 bytes? How can I read the data without me knowing what the max length of data form the server will be?
Typically, where there is not some specific intrinsic size of something, tcp protocols explicitly send the length of objects they are sending. One possible method for illustration:
size_t data_len = strlen(some_data_blob);
char lenstr[32];
sprintf(lenstr, "%zd\n", data_len);
send(socket, lenstr, strlen(lenstr));
send(socket, some_data_blob, data_len);
then when the receiver reads the length string, it knows exactly how mush data should follow (good programming practice is to trust but verify though -- if there is more or less data really sent -- say by an 'evil actor' -- you need to be prepared to handle that).
Not with respect to C# but a general answer on writing TCP application:
TCP is steam based protocol. It does not maintain message boundaries. So, the applications using TCP should take care of choosing the right method of data exchange between server and client. Its becomes more paramount if multiple messages gets sent and received on one connection.
One widely used method is to prepend the data message with the length bytes.
Ex:
[2 byte -length field][Actual Data].
The receiver of such data (be it server or client needs to decode length field, wait for until such event where as many bytes are received or raise an alarm on timeout and give up.
Another protocol that can be used is to have applications maintain message boundaries.
Ex:
`[START-of-MSG][Actual Data][END-of-MSG]
The reciever has to parse the data for Start-byte and End-byte (predefined by application protocol) and treat anything in between as data of interest.
hello i solved it with a list, i don't know the size of the complete package but i can read it in parts
List<byte> bigbuffer = new List<byte>();
byte[] tempbuffer = new byte[254];
//can be in another size like 1024 etc..
//depend of the data as you sending from de client
//i recommend small size for the correct read of the package
NetworkStream stream = client.GetStream();
while (stream.Read(tempbuffer, 0, tempbuffer.Length) > 0) {
bigbuffer.AddRange(tempbuffer);
}
// now you can convert to a native byte array
byte[] completedbuffer = new byte[bigbuffer.Count];
bigbuffer.CopyTo(completedbuffer);
//Do something with the data
string decodedmsg = Encoding.ASCII.GetString(completedbuffer);
I do this whith images and looks good, i thik than you dont know the size of the data if the porpouse is read a complete source with a unknow size
I was looking around for an answer to this, and noticed the Available property was added to TcpClient. It returns the amount of bytes available to read.
I'm assuming it was added after most of the replies, so I wanted to share it for others that may stumble onto this question.
https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.available?view=netframework-4.8

Categories

Resources