Sending multiple files on different threads Sockets c# - c#

I am working on a software that transfers multiple files between different computers but i am faced with the problem of concurrency. When both threads start sending using Task.Run() the bytes mumble up on the receiving side i.e the data clashes together. I have tried locking every possible part of my code that could cause the error all to no avail. This is part of my code.
//code to transfer asynchronously
public void StartTransferAsync(Socket socket)
{
Task.Factory.StartNew(() =>
{
lock (this)
{
uploader = new Uploader(this, socket);
uploader.Upload();
}
});
}
//code to receive the asynchronous files coming in
public byte[] DownloadData()
{
int total = 0;
int recv = 0;
int size = 0;
int dataleft = 0;
byte[] data;
byte[] dataSize = new byte[4];
recv = socket.Receive(dataSize, 0, 4, 0);
size = BitConverter.ToInt32(dataSize, 0);
Console.WriteLine($"Size received: {size}");
if (size > 100038)
{
Console.WriteLine("Shii here");
}
dataleft = size;
data = new byte[size];
while (total < size)
{
recv = socket.Receive(data, total, dataleft, 0);
total += recv;
dataleft -= recv;
}
return data;
}
Please help i really need this.

Related

Sending multiple files from C# to C

I have a wpf gui that I want to upload files from and send to a C client .
I want to send 3 files and for some reason 1 of them is being sent and written (but it adds 8 nulls in the end and removes 4 of the first letters in the file)
and in the other two when I try to receive the size it says their size is 0
I've been stuck on this problem for a while now and i'm becoming depserate as i'm probably missing a small thing , if any of u could give a hand that'll mean a lot ! I really wanna know whats the problem in my code.
I have the files paths in an array and sending it in main like so
C# Main
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5555);//switch the port
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(ipPoint);
listenSocket.Listen(1);
Socket clientSocket = listenSocket.Accept();
for (int i = 0; i < 1; i++)
{
SendFile(clientSocket, filePaths[i]);
}
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
SendFile(C# side)
public static void SendFile(Socket clientSocket, string filePath)
{
if (File.Exists(filePath))
{
FileInfo fi = new FileInfo(filePath);
long file_size = fi.Length;
byte[] preBuffer;
using (var memoryStream = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(memoryStream))
{
writer.Write(file_size);
}
preBuffer = memoryStream.ToArray();
byte[] fixedBuffer = new byte[4];
Array.Copy(preBuffer, 0, fixedBuffer, 0, 4);
Console.WriteLine(BitConverter.ToString(preBuffer));
Console.WriteLine(BitConverter.ToString(fixedBuffer)); //fixing the problem i had with the converting to array that it added 4 useless zeros.
clientSocket.Send(fixedBuffer); // sending size
}
byte[] data = new Byte[4096];
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
int actualRead;
do
{
actualRead = fs.Read(data, 0, data.Length);
clientSocket.Send(data);
file_size -= actualRead;
} while (file_size - filePath.Length > 0);
}
}
else
{
MessageBox.Show("File for the program is missing! lua/pcap/csv");
}
}
C Receive(built from 3 functions)
/*
============================================
General : function is responsible for receiving a length of data from the client
Parameters : sock - client socket to receive the data from
*buf - holds a pointer to the buffer that needs to update
bufsize - the length of the buffer
Return Value : returns TRUE when the data is read correctly
else, FALSE when there was a socket error or no bytes are received.
============================================
*/
bool recv_raw(SOCKET sock, void* buf, int bufsize)
{
unsigned char* pbuf = (unsigned char*)buf;
while (bufsize > 0) {
int num = recv(sock, pbuf, bufsize, 0);
if (num <= 0) { return false; }
pbuf += num;
bufsize -= num;
}
return true;
}
/*
===================================================
General : receives the length of the file and updates it
Parameters : sock - client socket to receive the data from
*filesize - holds a pointer to the size of the buffer that needs to update
filesize_len - the length of the file size pointer
Return Value : returns TRUE when the size is read correctly
else, FALSE when there was a socket error or no bytes are received.
===================================================
*/
bool recv_file_len(SOCKET sock, long* filesize)
{
if (!recv_raw(sock, filesize, sizeof(*filesize))) { return false; }
return true;
}
/*
================================================== =
General : writes to the lua file the data from the file
that was received in the socket
Parameters : sock - the socket between the client and server
*f - the file to write the data received to
Return Value : returns TRUE when everything was written to the file.
returns FALSE if there's no data received or detected a socket problem.
================================================== =
*/
bool write_data(SOCKET sock, FILE *f)
{
long filesize;//size of address
char buffer[BUFFER_SIZE];
if (!recv_file_len(sock, &filesize)) { return false; }
printf("file size (From C#) : %ld\n", filesize);
int n = recv_raw(sock, buffer, 8); // need to get the size of the name
if (filesize > 0)
{
do {
int num = min(filesize, BUFFER_SIZE);
if (!recv_raw(sock, buffer, num)) {
return false;
}
int offset = 0;
do
{
size_t written = fwrite(&buffer[offset], 1, num - offset, f);
if (written < 1) { return false; }
offset += written;
} while (offset < num);
filesize -= num;
} while (filesize > 0);
}
return true;
}
C Main
FILE* luafhandler = fopen("test.lua", "wb");//the new lua file
if (luafhandler == NULL)
{
fclose(luafhandler);
printf("GUI CONNECT lua file failed to open!\n");
}
FILE* pcapfhandler = fopen("test.pcap", "wb");//the new lua file
if (pcapfhandler == NULL)
{
fclose(pcapfhandler);
printf("GUI CONNECT pcap file failed to open!\n");
}
FILE* csvfhandler = fopen("AlgoTest.csv", "wb");//the new lua file
if (csvfhandler == NULL)
{
fclose(csvfhandler);
printf("GUI CONNECT csv file failed to open!\n");
}
else {
SOCKET sock1 = open_socket(5555, SERVER_IP);
bool check = write_data(sock1, luafhandler);
bool check1 = write_data(sock1, pcapfhandler);
bool check2 = write_data(sock1, csvfhandler);
fclose(luafhandler);
fclose(pcapfhandler);
fclose(csvfhandler);
}

Send Image Frames from C++ Server to C# Client using Named Pipe

I am noobie in IPC. I am trying to send the Image Frame from my C++ Server to C# Client. I have start learning about that and make a small Client and Server that In which my C++ Server sends Hello. I saw a related question and someone told to first convert the Image into Byte Array and then send that in same way as Hello Message but I am not able to do that.
My Basic Client Server Code
C++ Code:
Mat image = imread("IMG_0_10_34_45_2018_1.bmp");
uchar buffer[500][500];
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
buffer[i][j] = image.at<unsigned char>(i, j);
}
}
cout << "Server Creating Pipe\n";
HANDLE hPipe = ::CreateNamedPipe(_T("\\\\.\\pipe\\HyperPipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
PIPE_UNLIMITED_INSTANCES,
4096,
4096,
0,
NULL);
cout << "Server Created Succesfully";
ConnectNamedPipe(hPipe, NULL);
cout << "Sending Message to Client";
DWORD bytesWritten = 0;
WriteFile(hPipe, buffer, sizeof(buffer) * sizeof(uchar), &bytesWritten, NULL);
CloseHandle(hPipe);
return 0;
And C# Code:
static void Main(string[] args)
{
Console.WriteLine("Creating Client Pipe");
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "HyperPipe", PipeDirection.InOut);
Console.WriteLine("Pipe Created Successfully, Connecting to Server");
pipe.Connect();
Console.WriteLine("Successfully, Connected to Server");
using (StreamReader rdr = new StreamReader(pipe, Encoding.Unicode))
{
System.Console.WriteLine("Message from Server: " + rdr.ReadToEnd());
}
Console.ReadKey();
}
I also noticed that in my C++ Server I have to change the PIPE_TYPE to BYTE and also READMODE to BYTE. I am using OpenCV library for Image Processing so I can easily make Byte Array no issue with that.
So, Can Anyone Please tell me how to send that Byte Array from C++ to C#.
Or if possible that anyone can provide me the code for that
Thanks in Advance
Update:
No error is coming but at the client side i.e C# Side the the output of Message from Server is ????? .
To Send the Byte Array from Server to Client i.e the buffer just small changes in the WriteFile function is required.
WriteFile(hPipe, buffer, sizeof(buffer) * sizeof(uchar), &bytesWritten, NULL);
This method will send whole Byte Array to the Client
And also changing the buffer
int _count = 0;
UINT8 _imageBuffer[110592];
for (int _imageRow = 0; _imageRow < _image.rows; _imageRow++)
{
for (int _imageCol = 0; _imageCol < _image.cols; _imageCol++)
{
buffer[_count] = image.at<uchar>(_imageRow, _imageCol);
_count++;
}
}
I have hardCode the buffer Array because I known that my camera will only send 110592 byte to create one frame.
And On the Client Side just use Read function.
int _imageRowSize = 288;
int _imageColSize = 384;
int _count = 0;
byte[] buffer = new byte[_imageColSize * _imageRowSize];
Image<Gray, UInt16> image = new Image<Gray, UInt16>(_imageColSize,_imageRowSize);
Console.WriteLine("Creating Client Pipe");
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "HyperPipe", PipeDirection.InOut);
Console.WriteLine("Pipe Created Successfully, Connecting to Server");
pipe.Connect();
Console.WriteLine("Successfully, Connected to Server");
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
_count = 0;
int read = pipe.Read(buffer, 0, buffer.Length);
for (int _imageRow = 0; _imageRow < 288; _imageRow++)
{
for (int _imageCol = 0; _imageCol < 384; _imageCol++)
{
try
{
image.Data[_imageRow, _imageCol, 0] = (UInt16)(buffer[_count] * 255);
}catch(Exception exception)
{
Console.WriteLine(exception);
}
_count++;
}
}
if (read <= 0)
break;
ms.Write(buffer, 0, read);
}
}
CvInvoke.Imshow("Image", image);
}

C# UDP going slower then TCP

I'm trying to stream a video feed form the Xbox Kinect from a client to a server. I got it working with TCP but I could only get about 5 fps so now I'm trying it with UDP. UDP should be faster because of how the protocol works but it seems to be slower. Here is my post about the TCP (http://stackoverflow.com/questions/9627242/c-sharp-streaming-video-over-networkstream-tcpclient)
I can send this all the data I want over my LAN but I start losing a lot of packets if I push them out too fast. That is why I am using the Thread.Sleep(20); Increasing the chuck size speeds it up a lot but I'm at my max for sending over my LAN and if I understand correctly the max chunk size for sending over the internet is about 1500 bytes. If I only sent 1500 bytes at a time this would go really slow. I must be doing something wrong.
Here is the code.
private const int constChunkSize = 38400;
protected UdpClient udpObject;
private void HandleComm()
{
byte[] fullMessage = new byte[1228800];
byte[] byteReceived;
int currentIndex = 0;
IPEndPoint remoteIPEndPoint = new IPEndPoint(ip, port);
while (true)
{
byteReceived = udpObject.Receive(ref remoteIPEndPoint);
if (currentIndex + byteReceived.Length > 1228800)
{
int wtf = 0;
}
Array.Copy(byteReceived, 0, fullMessage, currentIndex, byteReceived.Length);
currentIndex += byteReceived.Length;
//Console.WriteLine("Recieved: " + currentIndex);
if (currentIndex == 1228800)
{
if (OnDataReceived != null)
{
FrameReceivedArgs args = new FrameReceivedArgs();
args.frame = new byte[fullMessage.Length];
fullMessage.CopyTo(args.frame, 0);
OnDataReceived(this, args);
}
currentIndex = 0;
Console.WriteLine("Done receiving" + DateTime.Now.Ticks);
}
}
}
public void sendData(byte[] data)
{
sending = true;
sendThread = new Thread(sendDataThread);
sendThread.Priority = ThreadPriority.Highest;
sendThread.Start(data);
}
private void sendDataThread(object tempData)
{
byte[] data = (byte[]) tempData;
int totalBytes = data.Length;
int currentBytes = 0;
int bufferLength = constChunkSize;
byte[] sendBytes = new byte[constChunkSize];
while (currentBytes < totalBytes)
{
if (totalBytes - currentBytes < constChunkSize)
bufferLength = totalBytes - currentBytes;
Array.Copy(data, currentBytes, sendBytes, 0, bufferLength);
currentBytes += bufferLength;
udpObject.BeginSend(sendBytes, bufferLength, new AsyncCallback(sendingData), udpObject);
Thread.Sleep(20);
//Console.WriteLine("Sent: " + currentBytes);
}
Console.WriteLine("done sending" + DateTime.Now.Ticks);
sending = false;
}
private void sendingData(IAsyncResult ar)
{
udpObject.EndSend(ar);
}

How to implement a lazy stream chunk enumerator?

I'm trying to split a byte stream into chunks of increasing size.
The source stream contains an unknown number of bytes and is expensive to read. The output of the enumerator should be byte arrays of increasing size, starting at 8KB up to 1MB.
This is very simple to do by simply reading the whole stream, storing it in an array and taking the relevant pieces out. However, since the stream may be very large, reading it at once is unfeasible. Also, while performance is not the main concern, it is important to keep system load very low.
While implementing this I noticed that it's relatively difficult to keep the code short and maintainable. There are a few stream related issues to keep in mind, too (for instance, Stream.Read might not fill the buffer even though it succeeded).
I did not find any existing classes that help for my case, nor could I find something close on the net. How would you implement such a class?
public IEnumerable<BufferWrapper> getBytes(Stream stream)
{
List<int> bufferSizes = new List<int>() { 8192, 65536, 220160, 1048576 };
int count = 0;
int bufferSizePostion = 0;
byte[] buffer = new byte[bufferSizes[0]];
bool done = false;
while (!done)
{
BufferWrapper nextResult = new BufferWrapper();
nextResult.bytesRead = stream.Read(buffer, 0, buffer.Length);
nextResult.buffer = buffer;
done = nextResult.bytesRead == 0;
if (!done)
{
yield return nextResult;
count++;
if (count > 10 && bufferSizePostion < bufferSizes.Count)
{
count = 0;
bufferSizePostion++;
buffer = new byte[bufferSizes[bufferSizePostion]];
}
}
}
}
public class BufferWrapper
{
public byte[] buffer { get; set; }
public int bytesRead { get; set; }
}
Obviously the logic for when to move up in buffer size, and how to choose what that size is could be altered.
Someone could also probably find a better way of handling the last buffer to be sent, as this isn't the most efficient way.
For reference, the implementation I currently use, already with improvements as per the answer by #Servy
private const int InitialBlockSize = 8 * 1024;
private const int MaximumBlockSize = 1024 * 1024;
private Stream _Stream;
private int _Size = InitialBlockSize;
public byte[] Current
{
get;
private set;
}
public bool MoveNext ()
{
if (_Size < 0) {
return false;
}
var buf = new byte[_Size];
int count = 0;
while (count < _Size) {
int read = _Stream.Read (buf, count, _Size - count);
if (read == 0) {
break;
}
count += read;
}
if (count == _Size) {
Current = buf;
if (_Size <= MaximumBlockSize / 2) {
_Size *= 2;
}
}
else {
Current = new byte[count];
Array.Copy (buf, Current, count);
_Size = -1;
}
return true;
}

sending binary files through TCP sockets c

I made a client & server that establishes a TCP connection through sockets, I'm trying to send binary data over the socket but I could only send txt or pdf files, I had no luck with exe files, I use fread and fseek to read the file and split it into a buffer. When I read the whole exe file it gets sent successfully but when I split it, it gets sent corrupted!
I read some books about sockets but I still don't know much and I have some questions.
is it okay to send the whole file in one send()?? or I should continue with sending it in small chunks?
Also, why exe files get corrupted when I send them in chunks?
Thank you!
Client Code (in c):
int bufSize = 10000;
int sentBytes = 0;
FILE * pFile;
long remainingBytes;
char * buffer;
size_t result;
pFile = fopen ( "D:\\file.exe" , "rb" );
fseek (pFile , 0 , SEEK_END);
remainingBytes = ftell (pFile);
rewind (pFile);
int bufferSize = remainingBytes > bufSize ? bufSize : remainingBytes;
buffer = (char*) malloc (sizeof(char)*bufferSize);
send(Socket, (char*)&remainingBytes, 4, 0);
while(remainingBytes > 0)
{
fseek (pFile , sentBytes , SEEK_SET);
result = fread(buffer,1,bufferSize,pFile);
if(bufferSize < remainingBytes)
{
send(Socket, buffer, bufferSize, 0);
}
else
{
send(Socket, buffer, remainingBytes, 0);
bufferSize = remainingBytes;
}
remainingBytes -= bufferSize;
sentBytes += bufferSize;
}
Server code (in c#)
try
{
int bufferSize = 200;
int len = 0;
int receivedBytes = 0;
int remainingBytes = len;
byte[] length = new byte[4];
//byte[] imgBuf = new byte[bufferSize];
int current = 0;
List<byte[]> coming = new List<byte[]>();
sockets[number].Receive(length,4,0);
len = BitConverter.ToInt32(length, 0);
remainingBytes = len;
bufferSize = len < bufferSize ? len : bufferSize;
while(receivedBytes < len)
{
if (remainingBytes > bufferSize)
{
coming.Add(new byte[bufferSize]);
//imgBuf = new byte[bufferSize];
sockets[number].Receive(coming[current], bufferSize, 0);
}
else
{
coming.Add(new byte[remainingBytes]);
//imgBuf = new byte[remainingBytes];
sockets[number].Receive(coming[current], remainingBytes, 0);
bufferSize = remainingBytes;
}
remainingBytes -= bufferSize;
receivedBytes += bufferSize;
current++;
//Array.Clear(imgBuf, 0, imgBuf.Length);
}
using (var stream = new FileStream(#"C:\receivedFile.exe",FileMode.Create))
{
using (var binaryWriter = new BinaryWriter(stream))
{
foreach (byte[] buffer in coming)
{
binaryWriter.Write(buffer);
}
}
}
}
catch (Exception ex)
{ this.setText(ex.Message, textBox2); }
Edit: Thanks for the help, I got it working :)
try
{
int bufferSize = 1024 * 100;
int len = 0;
int receivedBytes = 0;
int remainingBytes = len;
int reached = 0;
byte[] length = new byte[4];
byte[] imgBuf = new byte[bufferSize];
int current = 0;
sockets[number].Receive(length,4,0);
len = BitConverter.ToInt32(length, 0);
remainingBytes = len;
bufferSize = len < bufferSize ? len : bufferSize;
imgBuf = new byte[len];
while (reached < len)
{
reached += sockets[number].Receive(imgBuf, receivedBytes, remainingBytes, 0);
remainingBytes = len - reached;
receivedBytes = reached;
current++;
//Array.Clear(imgBuf, 0, imgBuf.Length);
}
using (var stream = new FileStream(#"C:\putty.exe",FileMode.Create))
{
using (var binaryWriter = new BinaryWriter(stream))
{
binaryWriter.Write(imgBuf);
}
}
Array.Clear(imgBuf, 0, imgBuf.Length);
}
catch (Exception ex)
{ this.setText(ex.Message, textBox2); }
You don't check how many bytes you actually received in sockets[number].Receive(coming[current], bufferSize, 0); . It doesn't have to be equal to the buffer size you have declared.
Additionaly, as said in comments, keeping whole file in memory is not a good idea.
In addition to checking the number of bytes received, you need to check the number of bytes sent by each send call -- if your TCP transmit window fills up, a send call might send less data than you requested, in which case the you'll need to resend the unsent data.
In general, you ALWAYS need to check the return value of your system calls to check for the all the various odd corner cases that can occur. Read the man pages for send(2) and recv(2) for a full list of everything that can happen.

Categories