So I have developed a C# app that runs on PC as a server, it captures the desktop of the PC and sends it as an image to either another PC or in this case an Oculus Quest.
When streaming to another PC it works fine. But when trying to stream to the Quest the buffer gets divided in so many parts that I cant get hold of a complete image. The image is basically 240 Kb size, you can see is not a small one (its a HD monitor).
The Server side (the PC) sends data like these:
AppendTextBox("Waiting for a client..." + Environment.NewLine);
theOtherClient = meAsServer.AcceptTcpClient();
AppendTextBox("Connected with " + theOtherClient.Client.RemoteEndPoint.ToString() + Environment.NewLine);
try {
NetworkStream srns = theOtherClient.GetStream();
while (currentProtocol == Protocol.Server) {
using (Image bmp = CaptureScreen.GetDesktopImage()) {
using (MemoryStream ms = new MemoryStream()) {
bmp.Save(ms, ImageFormat.Jpeg);
byte[] data = ms.ToArray();
byte[] dataLen = BitConverter.GetBytes(data.Length);
srns.Write(dataLen, 0, dataLen.Length);
srns.Write(data, 0, data.Length);
AppendTextBox("Image sent in -> " + data.Length.ToString() + " total bytes..." + Environment.NewLine);
}
}
Thread.Sleep(serverDelay); // Pause between images...
}
AppendTextBox("Closing server...");
theOtherClient.Close();
meAsServer.Stop();
} catch (Exception e) {
AppendTextBox("Exception: " + e.ToString() + Environment.NewLine);
theOtherClient.Close();
meAsServer.Stop();
}
And the Client (the Quest) tries to receive data like these:
meAsClient.Connect(myIP, myPort);
NetworkStream clns = meAsClient.GetStream();
byte[] imgInfo = new byte[8];
List<byte> imgData = new List<byte>();
meAsClient.ReceiveBufferSize = 65536;
while (currentProtocol == Protocol.Client) {
try {
if (meAsClient.Available > 0) {
int dataAmount = clns.Read(imgInfo, 0, meAsClient.Available);
int dataSize = BitConverter.ToInt32(imgInfo, 0);
MyDebugWindow.globalMyDebugUpdate("Image Size -> " + dataSize.ToString() + Environment.NewLine);
imgData.Clear();
do {
byte[] imgBuffer = new byte[meAsClient.Available];
dataAmount = clns.Read(imgBuffer, 0, meAsClient.Available);
imgData.AddRange(imgBuffer);
} while (meAsClient.Available > 0);
MyDebugWindow.globalMyDebugUpdate("Total Data -> " + imgData.Count.ToString() + Environment.NewLine);
imgData.CopyTo(theImgData);
}
} catch (Exception e) {
MyDebugWindow.globalMyDebugUpdate("Exception: " + e.ToString() + Environment.NewLine);
}
}
meAsClient.Close();
Both, client and server are running in separate threads. And they are both connected in a local network.
Any feedback, ideas, comments or upgrades to these code or method are truly welcome!
Related
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();
}
I have created a simple client to send HL7 formatted messages to a server. Unfortunately I do not have access to the server to see how the messages are coming in and what is being sent back. Right now my message sends but when I wait for a message back (ACK), it just sits there waiting.
Any advice is greatly appreciated.
try {
using (var client = new TcpClient())
{
client.Connect("10.25.60.8", 10000);
using (Stream stm = client.GetStream())
{
byte[] ba = Encoding.ASCII.GetBytes(segment1 + segment2 + segment3 + segment4 + segment5);
Console.WriteLine("Transmitting.....");
stm.Write(ba, 0, ba.Length);
Console.WriteLine("MessageSend reading response");
byte[] bb = new byte[1000];
int k = stm.Read(bb, 0, 1000);
for (int i = 0; i < k; i++)
Console.WriteLine(Convert.ToChar(bb[i]));
client.Close();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
This is how I create the message segments:
clnt p = new clnt();
patientAdmit r = new patientAdmit();
r.admitMessage = "MSH|^~\\&|MP|M1|MP|M2|201701011500||ADT^A01|HL7MSG00001|P|2.3|EVN|A01|201701011500||PID|||MRN222222||TEST^MICHAEL||19890101|M||C|1 MP STREET^^MARK^ON^L4C|GL|(416)123-1234|(647)123-1234|||||||NK1|1|TEST^BARBARA|WIFE||||||NK^NEXT OF KIN|PV1|1|I|20^201^01||||123456^TEST^DOC|||SUR||||ADM|A0|";
string vt = Convert.ToChar(11).ToString();
string cr = Convert.ToChar(13).ToString();
string fs = Convert.ToChar(28).ToString();
int startSegment2 = p.GetNthIndex(r.admitMessage, Convert.ToChar("|"), 12) + 1;
int startSegment3 = p.GetNthIndex(r.admitMessage, Convert.ToChar("|"), 16) + 1;
int startSegment4 = p.GetNthIndex(r.admitMessage, Convert.ToChar("|"), 16 + 21) + 1;
int startSegment5 = p.GetNthIndex(r.admitMessage, Convert.ToChar("|"), 16 + 21 + 10) + 1;
string segment1 = vt + r.admitMessage.Substring(0, startSegment2);
string segment2 = cr + r.admitMessage.Substring(startSegment2, startSegment3 - startSegment2);
string segment3 = cr + r.admitMessage.Substring(startSegment3, startSegment4 - startSegment3);
string segment4 = cr + r.admitMessage.Substring(startSegment4, startSegment5 - startSegment4);
string segment5 = cr + r.admitMessage.Substring(startSegment5, r.admitMessage.Length - startSegment5) + cr + fs;
You can simulate a server with most HL7 Editors. For example, grab the free trial of HL7 soup from their website, and create a new receiver on your desired port.
When you send in your messages they will respond straight back with an ACK message generated from your message.
In the reciever settings, you can even force the response to be an error or reject ACK so you can test your client.
Hello I'm trying to implement a server and client couple that can transfer files of any kind and any size but there is a problem I somehow corrupt files. I tried lots of methods but can't figure it out. So basicly I can connect ,I can understand which file does client want, and can send it through sockets. When I try to open that file it shows me an error message(Tried winrar, mp4, avi files) Here is my code:
//Server
private void Receive(string receivedFileName, string fileSize)
{
try
{
int receivedBytesLen = 0;
byte[] incomingFile = new byte[int.Parse(fileSize)];
activity.AppendText("Preparing to download... \n");
while (incomingFile != null && int.Parse(fileSize) > receivedBytesLen)
{
tempSocket.Receive(incomingFile);
receivedBytesLen = incomingFile.Length;
int fileNameLen = BitConverter.ToInt32(incomingFile, 0);
File.WriteAllBytes(fileDir + "//" + receivedFileName, incomingFile);
}
activity.AppendText("File saved to " + fileDir + "\n");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//////////////////////////////////////////////////////////////////////
//server option 2
private void Receive(string receivedFileName, string fileSize)
{
try
{
byte[] incomingFile = new byte[10124 * 5000];
activity.AppendText("Preparing to download... \n");
BinaryWriter bWrite = new BinaryWriter(File.Open(folderBrowserDialog1.SelectedPath + "//" + receivedFileName, FileMode.Append));
int receivedBytesLen = tempSocket.Receive(incomingFile, incomingFile.Length, 0);
int fileNameLen = BitConverter.ToInt32(incomingFile, 0);
//string fileName = Encoding.UTF8.GetString(incomingFile, 4, fileNameLen);
//bWrite.Write(incomingFile, 4 + fileNameLen, receivedBytesLen - 4 - fileNameLen);
while (receivedBytesLen > 0)
{
receivedBytesLen = tempSocket.Receive(incomingFile, incomingFile.Length, 0);
if (receivedBytesLen == 0)
{
bWrite.Close();
}
else
{
bWrite.Write(incomingFile, 0, receivedBytesLen);
}
}
activity.AppendText("File saved to " + fileDir + "\n");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/////////////////////////////////////////////////////////////////////
//client
private void Upload_Click(object sender, EventArgs e)
{//Uploads selected file after clicking upload button.
try
{
if (clientSocket.Connected)
{
byte[] buffer = new byte[1024];
byte[] sendingFile = null;
sendingFile = File.ReadAllBytes(openFileDialog1.FileName);
FileInfo f = new FileInfo(openFileDialog1.FileName);
string fileSize = f.Length.ToString();
buffer = Encoding.Default.GetBytes(getUserName.Text + "Upload" + openFileDialog1.SafeFileName + "size" + fileSize + "end");
clientSocket.Send(buffer);
activityLog.AppendText("Sending File \n");
int bytesToBeSent = sendingFile.Length;
int bytesActuallySent = 0;
while(bytesActuallySent < bytesToBeSent){
bytesActuallySent += clientSocket.Send(sendingFile, bytesActuallySent, bytesToBeSent -bytesActuallySent, 0);
}
activityLog.AppendText("File Sent.\n");
}
}
catch(Exception ex){
MessageBox.Show(ex.Message);
}
}
server option #2 is better. But there are some improvements
socket receive buffer is limited decided by OS, generally is 8192
use FileStream in client and server and do not forget to close filestream after file download
client:
FileStream fileStream = new FileStream(filePath, FileMode.Open)
byte[] buff = new byte[8192];
do
{
bytesRead = fileStream.Read(buff, 0, buff.Length);
sock.send(dataSock, buff, bytesRead);
}while (bytesRead > 0);
fileStream.close();
server:
FileStream fileStream = new FileStream(filePath, FileMode.Open)
do
{
bytesRead = sock.receive(buff, 0, buff.Lenght);
fileStream.Write(buff, 0, bytesRead );
}while (bytesRead > 0);
fileStream.close();
In order to satisfy ANY sized file you need an option #3, one that reads a block of bytes til all bytes are received, your option #1 wouldn't do so well on a 3 GIG file running on 2 GIG box...
Here is a link: http://www.yoda.arachsys.com/csharp/readbinary.html
I like option #2 from this link.
However in the example they write to a memoryStream, you should write to a filestream, the target file.
I am trying to send files with a bunch of strings from Android client to C# server. The strings, among other things, will also contain details with regards to the file being sent eg: File Size, File Name, etc. The issue I am having is that all the file bytes is not received thus the original file cannot be reconstructed at the destination even though I can properly retrieve all the strings.
My C# Server Code
while (true)
{
Socket socket = listener.AcceptSocket();
setStatus(socket.RemoteEndPoint + " Connected");
try
{
// Open the stream
NetworkStream stream = new NetworkStream(socket);
System.IO.StreamReader sr = new StreamReader(stream);
//Get string data
//********************************************
Teststr = sr.ReadLine();
setStatus(Teststr);
FileSize = sr.ReadLine();
long fileSizeLong = Convert.ToInt64(FileSize);
int length = (int)fileSizeLong;
setStatus("File size: " + length + " bytes");
//********************************************
//read bytes to buffer
byte[] buffer = new byte[length];
int toRead = (int)length;
int read = 0;
while (toRead > 0)
{
int noChars = stream.Read(buffer, read, toRead);
read += noChars;
toRead -= noChars;
}
setStatus("File Recieved. Total bytes: " + Convert.ToString(buffer.Length));
setStatus("Saving File");
String recievedPath = "C:\\Test\\";
BinaryWriter bWrite = new BinaryWriter(File.Open(recievedPath + "Test.png", FileMode.Create));
bWrite.Write(buffer);
setStatus("File Saved to: " + recievedPath);
bWrite.Flush();
bWrite.Close();
stream.Flush();
stream.Close();
}
catch (Exception e)
{
setStatus(e.Message);
}
setStatus("Disconnected");
socket.Close();
}
My Android Client Code
File file = new File(configstr[2]); //create file instance
try {
client = new Socket(configstr[0], Integer.valueOf(configstr[1]));
//Read file
fileInputStream = new FileInputStream(file);
outputStream = client.getOutputStream();
//Output database details to stream
//*****************************************
//Holds the string before conversion to bytes
String text = "";
text = "Test\n";
outputStream.write(text.getBytes());
text = String.valueOf(file.length()) + "\n";
outputStream.write(text.getBytes());
//*****************************************
outputStream.flush();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileInputStream.read(b)) != -1) {
bos.write(b, 0, bytesRead);
}
byte[] bytes = bos.toByteArray();
outputStream.write(bytes);
outputStream.flush();
return true;
} catch (UnknownHostException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
NOTE: The code works well if I only send one string, eg: If I only send file size.
Any better way of getting this to work as I am trying to send many strings through the stream as well as binary data from the file.
BufferedWriter with flush() at the end of every write() solved the issue for me.
Thanks for reading, I genuinely appreciate that I am asking a lot of whoever reads this.
I have to cut a physical file into 4096 kB chunks for upload. I can pick them up from the "other end" easy enough and remake them.
I appreciate there is a lot of information in this post and this one but I am struggling how to fit this all together elegantly
The idea is simply to cut files bigger than 4096kB into smaller parcels. To make it worse: if there is a way to synchronously Queue the send of the files without them having to be put on the local disk (i.e. work only in memory) I would really like that..
//Pseudocode:
Queue queue = new Queue();
byte[] currentChunk ;
int i =0;
while(currentChunk = openFileinChunks(filename, 4194304)) //4096 kB
{
HTTPPoster mypost = new HTTPPoster();
mypost.add(currentChunk);
//need comparison here - to know when last loop is happening to use different name :-/ for this next bit
mypost.uploadedName(filename+"."+ i.ToString().PadLeft(6, '0');
queue.Enqueue(mypost);
i++;
}
do
{
HTTPPoster Post = (HTTPPoster) queue.Dequeue();
Post.Run();
} while (queue.Count != 0);
class HTTPPoster{
byte[] sendable;
string tmpname;
public void add(byte[] toPost)
{
sendable = toPost;
}
public void uploadedName(string name)
{
tmpname = name;
}
public void Run()
{
//[preferably some condensed reworked code to replace this] **
}
}
**: Upload files with HTTPWebrequest (multipart/form-data)
I found this article http://blogs.msdn.com/b/johan/archive/2009/03/30/1080526.aspx very handy when trying to do something similar.
The approach in that article is relatively straightforward: you set up the web request then write chunks of data to the stream. However, by setting AllowWriteStreamBuffering to false, you prevent the request from buffering the whole file in memory.
The problem with your current approach is that it appears to keep everything in memory - this might cause you problems with larger files.
What does the server component of this look like? That will probably dictate the precise method you use to send the file.
Edit:
What about this?
int bytesRead;
int bufferSize = 4194304;
byte[] buffer = new byte[bufferSize];
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
int i = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
string postFileName = Path.GetFileName(filePath) + "." + i++.ToString().PadLeft(10, '0');
if (bytesRead < bufferSize)
{
postFileName = Path.GetFileName(filePath) + ".terminus";
}
PostFileChunk(buffer, bytesRead, postFileName);
}
}
This will read the file in blocks of 4MB, then call the PostFileChunk method (your HTTPPoster could come in to play here) to send the data to the server.
Keep in mind that when you are writing the chunk to the post in your Run method, use the bytesRead - because we are reusing the buffer, if the last read is less than bufferSize, it will still contain some of the data from the previous read. bytesRead will ensure that these characters don't get written.
this works, I have reduced it to 4096 B (not 4096kB) "chunks" but the principle is the same
NB: there is a small amount of object referencing that is my own - a thing I use called the jsonFolder and jsonDomain, which basically holds the username, password and url and file info.. you should be able to follow this logic though.. i will try to make the time to post this to a tutorial (including the PHP serverSide code, and the incron rebuilder)
/******
* the terminus file format is weird
* basically it goes like this
* tmp/myfilename.ext.00000000001 4kB
* tmp/myfilename.ext.00000000002 4kB
* tmp/myfilename.ext.00000000003 4kB
* tmp/myfilename.ext.00000000004 4kB
* tmp/myfilename.ext.terminus <=4kB
* this will re-built here to
* dir/myfilename.ext >16kB <20kB
*/
class classActionType_clientPush : classActionType
{
string relpath = "";
jsonFolder myFolder;
jsonDomain myDomain;
Queue<HTTPPoster> queue = new Queue<HTTPPoster>();
/// <param name="relativeLocalFilePath">
/// this "relativeLocalFilePath" refers to path RE: the ~localFolder~ - this class will cut the file and upload it in 4096kB chunks
/// </param>
/// <param name="folder">
/// use this for the folder pathing
/// </param>
/// <param name="domain">
/// this is for the credentials and the url
/// </param>
public void setPath(string relativeLocalFilePath, jsonFolder folder, jsonDomain domain)
{
string tmppath = folder.localFolder + relativeLocalFilePath;
if (File.Exists(tmppath))
{
relpath = relativeLocalFilePath;
myFolder = folder;
myDomain = domain;
}
else
{
throw new Exception("classActionType_clientPull.setPath():tmppath \"" + tmppath + "\" does not already exist");
}
}
public override void action()
{
if (relpath == "")
{
throw new Exception("classActionType_clientPull.action():relpath cannot be \"\"");
}
/***
* split it into chunks and copy file to server
*/
try
{
int bytesRead;
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
string filePath = myFolder.localFolder + relpath;
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
int i = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
string postFileName = Path.GetFileName(filePath) + "." + i++.ToString().PadLeft(10, '0');
if (bytesRead < bufferSize)
{
postFileName = Path.GetFileName(filePath) + ".terminus";
}
HTTPPoster mypost = new HTTPPoster();
mypost.add(buffer);
mypost.setBytes(bytesRead);
mypost.setDomain(this.myDomain);
mypost.uploadedName(postFileName);
queue.Enqueue(mypost);
Debug.WriteLine(" nof: HTTPPoster.action() loop counter " + i + "");
}
}
do
{
HTTPPoster Post = (HTTPPoster)queue.Dequeue();
Post.Run();
} while (queue.Count != 0);
}
catch (Exception ex)
{
Debug.WriteLine(" nof: HTTPPoster.action() failed\r\n" + ex.Message + "\r\n" + ex.StackTrace);
}
}
}
class HTTPPoster
{
byte[] sendable;
string filename;
int bytes;
jsonDomain myDomain;
public void add(byte[] b)
{
sendable = b;
}
public void uploadedName(string p)
{
filename = p;
}
public void setDomain(jsonDomain domain)
{
myDomain = domain;
}
public void setBytes(int bytesRead)
{
bytes = bytesRead;
}
public void Run()
{
try
{
/***
* this does the actual post (!gulp)
*/
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(myDomain.url + "/io/clientPush.php");
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream rs = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
string formitem;
byte[] formitembytes;
classHasher hash = new classHasher();
rs.Write(boundarybytes, 0, boundarybytes.Length);
formitem = string.Format(formdataTemplate, "username", myDomain.user);
formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
rs.Write(formitembytes, 0, formitembytes.Length);
rs.Write(boundarybytes, 0, boundarybytes.Length);
formitem = string.Format(formdataTemplate, "password", hash.Decrypt(myDomain.password, "saltysaltsalt"));
formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
rs.Write(formitembytes, 0, formitembytes.Length);
rs.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, "file", filename, "multipart/mixed");
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
rs.Write(sendable, 0, bytes);
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
rs.Write(trailer, 0, trailer.Length);
rs.Close();
WebResponse wresp = null;
try
{
wresp = wr.GetResponse();
Stream myStream = wresp.GetResponseStream();
StreamReader myReader = new StreamReader(myStream);
Debug.WriteLine(" nof: HTTPPoster.Run() all ok \r\n" + myReader.ReadToEnd());
}
catch (Exception ex)
{
Debug.WriteLine(" nof: HTTPPoster.Run() finished\r\n" + ex.Message + "\r\n" + ex.StackTrace);
if (wresp != null)
{
wresp.Close();
wresp = null;
}
}
finally
{
wr = null;
}
}
catch (Exception ex)
{
Debug.WriteLine(" nof: HTTPPoster.Run() !ERROR! \r\n" + ex.Message + "\r\n" + ex.StackTrace);
}
}
}
My solution:
void LikeThat(byte[] file)
{
var ms = new System.IO.MemoryStream(file);
var b= new byte[4096];
while (ms.Length > 0)
{
ms.Read(b, 0, 4096);
//now b contains your chunk, just transmit it!
}
}