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.
Related
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!
I send a 4 MB file by tcp to the local server. But the file is stored at 36 MB on the local server.
What is the problem with?
I convert file to string (base64) and add to my json. then Convert json to byte[] and send it.
Client send byte to server:
await nwStream.WriteAsync(json, 0, json.Length);
NetworkStream streams = client.GetStream();
int Q = 0;
int M = json.Length;
int ss = 150001;
bool go = true;
while (go)
{
if(M< ss)
{
go = false;
ss = M;
}
if (M < 0)
{
go = false;
ss = M + ss;
}
await streams.WriteAsync(json, Q,ss);
Q += ss;
M -= ss;
}
and Server side get byte[]:
Byte[] bytes = new Byte[150001];
int i;
try
{
// Loop to receive all the data sent by the client.
while ((i = await stream.ReadAsync(bytes, 0, bytes.Length)) != 0)
{
// bytes contains received data in byte[].
// Translate data bytes to a UTF-8 string.
byte[] receivedBuffer = new byte[i];
Array.Copy(bytes, receivedBuffer, i);
data += System.Text.Encoding.UTF8.GetString(receivedBuffer);
if (data.IndexOf("}") > 0)
{
break;
}
}
}
catch (Exception ex)
{
}
Edit:
and Save File, I Encoding 'data' to UTF8 string, then convert to DeserializeObject.
var pi = Convert.FromBase64String(picbas64);
var x = (Bitmap)((new ImageConverter()).ConvertFrom(pi));
string path = #"pic\Operation\" + name + ".jpg";
var ZZ = x;
ZZ.Save(path);
return path;
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 tried every solution I could find but nothing seems to work. Anything other than text files becomes corrupted; someone said that TCP can't send more than 8KB, so I tried to fix the problem and I think I did. Now, when I send a text file (no matter what size it is), it reaches perfectly but anything else gets corrupted. I know the code for the cutting is expensive to performance but I am going to think about that later.
Here is my sender code:
private string SendFile(string tosend, string tosendname)
{
ipadd = IPAddress.Parse(textBox2.Text);
ep = new IPEndPoint(ipadd, 6112);
Sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
Sender.Connect(ep);
Thread.Sleep(100);
byte[] filetosend = System.IO.File.ReadAllBytes(tosend);
FileStream fs = new FileStream(tosend, FileMode.Open, FileAccess.Read);
//Read byte from image
fs.Read(filetosend, 0, filetosend.Length);
fs.Flush();
fs.Close();
int countt = filetosend.Count();
int dividedcount = countt / 7000;
Sender.Send(Encoding.ASCII.GetBytes("filesize#" + filetosend.Count().ToString()));
Thread.Sleep(500);
List<byte> cuttedtosend = new List<byte>();
for (int counti = 0; counti < dividedcount; counti++)
{
cuttedtosend = new List<byte>();
for (int index = 0; index < 7000; index++)
{
cuttedtosend.Add(filetosend[(filetosend.Count() - countt) + index]);
}
Sender.Send(cuttedtosend.ToArray());
Thread.Sleep(100);
countt -= 7000;
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Countt = " + countt + "\n"); });
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Counti = " + counti + "\n"); });
}
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Done"); });
cuttedtosend = new List<byte>();
for (int index = filetosend.Count() - countt; index < filetosend.Count(); index++)
{
//richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText(index + "this is 2 \n"); });
cuttedtosend.Add(filetosend[index]);
}
Sender.Send(cuttedtosend.ToArray());
countt -= countt;
return "";
}
And here is my receive code:
private async void StartReceiving()
{
List<byte> neededbytes = new List<byte>();
receivedbyte = new byte[InputForm.s];
Receiver.Bind(new IPEndPoint(IPAddress.Parse("0"), 6112));
Receiver.Listen(1000);
string filename = "Downloadedfile";
bool cont = false;
while (true)
{
Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
Client = Receiver.Accept();
int filesize = 0;
byte[] receivechecker = new byte[100];
Client.Receive(receivechecker);
if(Encoding.ASCII.GetString(receivechecker).Contains("filesize#"))
{
filesize = Convert.ToInt32(Encoding.ASCII.GetString(receivechecker).Remove(0, 9));
Client.Receive(receivechecker);
}
if (Encoding.ASCII.GetString(receivechecker).Contains("#100254#"))
{
string[] splttedtext = Encoding.ASCII.GetString(receivechecker.ToArray()).Split('#');
if (splttedtext[0] == "mess")
{
MessageBox.Show(splttedtext[2]);
}
else if (splttedtext[0] == "filename")
{
//MessageBox.Show(splttedtext[2]);
filename = splttedtext[2];
//filename.Replace(#"\", #"/");
cont = true;
}
}
else
{
List<byte> tosave = new List<byte>();
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText(filesize.ToString() + "\n"); });
int countt = filesize / 7000;
FileStream writer = File.Create("DownloadedFile.jpg");
for (int counti = 0; counti < countt; counti++)
{
byte[] toadd = new byte[7000];
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Counti = " + counti.ToString() + "\n"); });
Client.Receive(toadd);
writer.Write(toadd,0,toadd.Count());
neededbytes.AddRange(toadd);
filesize -= 7000;
}
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText(filesize.ToString() + "\n"); });
byte[] toadds = new byte[filesize];
Client.Receive(toadds);
writer.Write(toadds,0,toadds.Count());
writer.Close();
neededbytes.AddRange(toadds);
filesize -= filesize;
}
}
Thanks in advance :D
Edit:
I just tried Sending a 7mb text file and it reached complete.......
The most immediate problem is that you're saving bytes that you didn't necessarily receive. For example, you have:
for (int counti = 0; counti < countt; counti++)
{
byte[] toadd = new byte[7000];
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Counti = " + counti.ToString() + "\n"); });
Client.Receive(toadd);
writer.Write(toadd,0,toadd.Count());
neededbytes.AddRange(toadd);
filesize -= 7000;
}
The documentation for Receive says that the method will receive up to the number of bytes you request. It's not uncommon for it to return fewer bytes than you requested, especially at the end of the file (since it couldn't receive more than the file length).
You need to write:
var bytesRead = Client.Receive(toadd);
writer.Write(toadd, 0, bytesRead); // only write as many bytes as you've read
In general, your code is pretty convoluted, and you have several other possible problems just waiting to bite you. For example, the code that sends the file size sleeps for 500 ms, which just happens to be enough time for the receiver to read just the number of bytes sent. Without that sleep, your code would fail.
You have code to receive the file name, but no code to send it.
I would suggest that you eliminate the ASCII tags and send things in binary. Below is your rewritten Send method.
private string SendFile(string tosend, string tosendname)
{
ipadd = IPAddress.Parse(textBox2.Text);
ep = new IPEndPoint(ipadd, 6112);
Sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
Sender.Connect(ep);
byte[] filetosend = System.IO.File.ReadAllBytes(tosend);
byte[] filesizeBytes = BitConverter.GetBytes(filetosend.Length);
Sender.Send(filesizeBytes); // sends the length as an integer
// note: You could use Socket.Send(filetosend) here.
// but I'll show an example of sending in chunks.
int totalBytesSent = 0;
while (totalBytesSent < filetosend.Length)
{
int bytesLeft = filetosend.Length - totalBytesSent;
int bytesToSend = Math.Min(bytesLeft, 7000);
Sender.Send(filetosend, totalBytesSent, bytesToSend);
richTextBox1.Invoke((MethodInvoker)delegate
{ richTextBox1.Append(totalBytesSent + " bytes sent\n"); });
totalBytesSent += bytesToSend;
}
richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("Done"); });
return "";
}
The receiver code is similarly simplified:
private async void StartReceiving()
{
Receiver.Bind(new IPEndPoint(IPAddress.Parse("0"), 6112));
Receiver.Listen(1000);
string filename = "Downloadedfile";
bool cont = false;
while (true)
{
Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
Client = Receiver.Accept();
// read the length
byte[] filesizeBytes = new byte[4];
int totalBytesReceived = 0;
while (totalBytesReceived < 4)
{
int bytesRead = Client.Receive(
filesizeBytes, totalBytesReceived, 4-totalBytesReceived);
totalBytesReceived += bytesRead;
}
int filesize = BitConverter.ToInt32(filesizeBytes);
richTextBox1.Invoke((MethodInvoker)delegate
{ richTextBox1.AppendText(filesize.ToString() + "\n"); });
// now read the file
using (FileStream writer = File.Create("DownloadedFile.jpg"))
{
byte[] readBuffer = new byte[7000];
totalBytesReceived = 0;
while (totalBytesReceived < filesize)
{
int bytesToRead = Math.Min(7000, filesize - totalBytesReceived);
int bytesRead = Client.Receive(readBuffer, 0, bytesToRead);
totalBytesRead += bytesRead;
writer.Write(readBuffer, 0, bytesRead);
richTextBox1.Invoke((MethodInvoker)delegate
{ richTextBox1.AppendText("Read " + bytesRead.ToString() + "bytes\n"); });
}
richTextBox1.Invoke((MethodInvoker)delegate
{ richTextBox1.AppendText("Done. " + totalBytesRead.ToString() + " bytes\n"); });
}
}
If you want to send the file name, then I would suggest converting it to UTF8 (Encoding.UTF8.GetBytes(filename)), then send an int (4 bytes) that says how long it is, and then the buffer. To receive it, read the 4-byte filename length like I showed how to read the file size, then that many bytes for the file name, and convert back to a string (Encoding.UTF8.GetString(bytes, 0, filenameLength)).
Please excuse any typos or minor errors in the code. I'm doing this from memory and trying to keep somewhat with your coding style.
i suspect that you are expecting the same blocks that you send to be received; ie that record boundaries will be preserved. This is not so. TCP guarantees that every byte sent will be received and that order is preserved; but you could do 1 large 10k send and receive 10k 1 byte messages.
i have written a little "Update Programm" to keep an .exe up to date for the rest of my dev team. It used to work fine, but suddenly it stopped working.
I already noticed the problem: my remote stream does not start to read.
Uri patch = new Uri("http://********/*********/" + GetVersion().ToString() + ".exe");
Int64 patchsize = PatchSize(patch);
var CurrentPath = String.Format("{0}\\", Environment.CurrentDirectory);
Int64 IntSizeTotal = 0;
Int64 IntRunning = 0;
string strNextPatch = (version + ".exe");
using (System.Net.WebClient client = new System.Net.WebClient())
{
using (System.IO.Stream streamRemote = client.OpenRead(patch))
{
using (System.IO.Stream streamLocal = new FileStream(CurrentPath + strNextPatch, FileMode.Create, FileAccess.Write, FileShare.None))
{
int intByteSize = 0;
byte[] byteBuffer = new Byte[IntSizeTotal];
while ((intByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
streamLocal.Write(byteBuffer, 0, intByteSize);
IntRunning += intByteSize;
double dIndex = (double)(IntRunning);
double dTotal = (double)byteBuffer.Length;
double dProgressPercentage = (dIndex / dTotal);
int intProgressPercentage = (int)(dProgressPercentage * 100);
worker.ReportProgress(intProgressPercentage);
}
streamLocal.Close();
}
streamRemote.Close();
GetVersion() only returns the current version number of the current server version of the .exe.
The problem lies here:
while ((intByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
My streamRemote just does not return any bytes so this while clause is not filled.
Any advice for me?
I believe the problem is on the server. I'd run some checks:
Has anything changed on the configuration of the web server that stops you from downloading executables?
Are you connecting through a proxy?
Can you manually get to the same URL (under the same user credentials of your application)?