Difference between .net TcpClient and Delphi2010 IdTCPClient - c#

I have the following code written in delphi2010:
TCPClient := TidTcpClient.Create;
TCPClient.Host := '192.168.12.131';
TCPClient.Port := 1312;
TCPClient.Connect;
TCPClient.IOHandler.WriteLn('msg', TEncoding.ASCII);
answer := TCPClient.IOHandler.ReadLn(TEncoding.ASCII);
This code works well - i get answer.
And i have the following C# code:
var client = new TcpClient();
client.Connect(endpoint);
var stream = client.GetStream();
var msgData = System.Text.Encoding.UTF8.GetBytes("msg");
stream.Write(msgData, 0, msgData.Length);
var answerData = new Byte[256];
var asnwerLength = stream.Read(answerData, 0, answerData.Length);
And it didn't work - request timeout.
What is difference between these two parts?

Your delphi code is writing (by the looks of things) a complete line - presumably with some line ending characters. Maybe the server is expecting those?
Try:
var client = new TcpClient();
client.Connect(endpoint);
var stream = client.GetStream();
var msgData = System.Text.Encoding.UTF8.GetBytes("msg\r\n"); //Include line ending. Might just need \r or \n by themselves - consult server documentation, if available
stream.Write(msgData, 0, msgData.Length);
var answerData = new Byte[256];
var asnwerLength = stream.Read(answerData, 0, answerData.Length);
Also, you need to bear in mind that stream.Read will return as much data as it currently has available - which may be less than a complete message from the server, or may include (parts of) several messages from the server. If you want to duplicate the ReadLn behaviour, you'll need to search in the receive buffer for end of line characters yourself.

Related

How to set a correct buffer size for TCP message responses

This is how I currently send data to an external TCP server
byte[] data = new byte[0] /* the data to send */;
TcpClient client = new TcpClient("127.0.0.1", 3000); // connect to the tcp server
NetworkStream stream = client.GetStream();
await stream.WriteAsync(data, 0, data.Length);
data = new byte[256]; // set the buffer size
int responseBytes = await stream.ReadAsync(data, 0, data.Length); // store the response to the buffer
string responseData = System.Text.Encoding.ASCII.GetString(data, 0, responseBytes);
stream.Close();
client.Close();
For the response I have to setup the buffer size here new byte[256]. But what if the response is greater than this size? I can't determine the correct size because I'm just connecting to his external server, send a message to it and expect a response. Is there a way I can make this dynamic?
As a sidenote: I'm sending various HL7 messages to clinic servers and they will send back HL7 ACK messages as a response. This gives some information about HL7 ACK messages
https://healthstandards.com/blog/2007/02/01/ack-message-original-mode-acknowledgement/
An example ACK could be
MSH|^~&|CATH|StJohn|AcmeHIS|StJohn|20061019172719||ACK^O01|MSGID12349876|P|2.3
MSA|AA|MSGID12349876
For the response I have to setup the buffer size here new byte[256]. But what if the response is greater than this size?
Then you call stream.ReadAsync() and append your buffer (or the decoded string) to a larger buffer until you know you have received the entire message, which you need to do anyway: the Write() from one end of the socket does not need to correspond to one Read() on the other end. Multiple writes can be read in a single read, or the other way around.
So something like this:
data = new byte[256]; // set the buffer size
var builder = new StringBuilder();
do
{
int responseBytes = await stream.ReadAsync(data, 0, data.Length); // store the response to the buffer
string responseData = System.Text.Encoding.ASCII.GetString(data, 0, responseBytes);
builder.Append(responseData);
} while (responseBytes > 0)
Do note that this happens to work with ASCII, as it doesn't have multibyte characters. Were it UTF-8 or a similar encoding, the 256th byte could be the start of a character which continues into the next read, i.e. byte 1 (and perhaps 2) of the next read.
This code also assumes you want to keep reading until the connection is closed (then responseBytes = 0). If this protocol has a length prefix or message terminator, you have to handle those.
Usually you don't want to implement this low-level stuff yourself, aren't there libraries available that handle the HL7 protocol?

Calling Node.js service via C# when the response size is unknown

I have some C# that is successfully calling my TCP service (running on Node.js) and receiving a response. My code looks similar to this:
string html = Console.ReadLine();
Byte[] htmlBytes = System.Text.Encoding.ASCII.GetBytes(html);
TcpClient client = new TcpClient("127.0.0.1", 5000);
NetworkStream stream = client.GetStream();
stream.Write(htmlBytes, 0, htmlBytes.Length);
Console.WriteLine("Message has been sent");
Byte[] responseBytes = new Byte[50000];
int numberOfBytes = stream.Read(responseBytes, 0, responseBytes.Length);
My questions is in regarding to this code:
Byte[] responseBytes = new Byte[50000];
int numberOfBytes = stream.Read(responseBytes, 0, responseBytes.Length);
Because responseBytes is passed by reference into stream.Read(...), it must be initialized, so I've chosen a size of 50000. If the response is more than 50000, then I only receive the first 50000 bytes.
This works fine if my response is 50000 bytes or smaller, but what if I don't know what the response size will be? Is there a best practice for receiving large responses or handling a situation where the byte array returned is unknown?
this may be super simplistic of an answer, but wouldn't it make sense to just have an arbitrary variable as a 'byte' for the size. Then as you process responses, that variable gets assigned a new value each time, before the initialization of the array?

Using TcpClient on websocket receive data get \0\0\0\0

I have establish a connection with a websocket , i want to receive message from it. Following is my code for receiving message from the websocket.
//mClient is my TCP connection
byte[] bytes;
NetworkStream netStream;
string returndata;
while(true)
{
bytes = new byte[mClient.ReceiveBufferSize];
netStream = mClient.GetStream();
netStream.Read(bytes, 0, (int)mClient.ReceiveBufferSize);
returndata = Encoding.UTF8.GetString(bytes);
Console.WriteLine("This is what the host returned to you: " + returndata);
}
The data should be some json array when I open with browser , but i have receive weird data like
??\0\0\0\0\0\0\0\0\0\0\
And the second loop onwards is forever
\0\0\0\0\0\0\0\0\0\0\0
I have seen a Similar Question but i have no idea on his answer. May I know how to fix this thing and what is the problem ?
Just read the stream with a StreamReader instead of fiddling with array buffers and the encoding by yourself:
//mClient is my TCP connection
StringBuilder returndata = new StringBuilder();
Console.Write("This is what the host returned to you: ");
// the StreamReader handles the encoding for you
using(var sr = new StreamReader(mClient.GetStream(), Encoding.UTF8))
{
int value = sr.Read(); // read an int
while(value != -1) // -1 means, we're done
{
var ch = (char) value; // cast the int to a char
Console.Write(ch); // print it
returndata.Append(ch); // keep it
value = sr.Read(); // read next char
}
}
Console.WriteLine(" done.");
capture the result in a StringBuilder so you can convert that to a string if the loop ends (based on whatever condition that will be)
It won't work like that. WebSockets uses a framing protocol that you have to parse. Your JSON payload will be wrapped in one or multiple frames you need to read and parse.
https://www.rfc-editor.org/rfc/rfc6455#section-5.2

How do I get a Named Pipe to block in C#?

I'm writing a C# Windows Service (server) that will need to receive messages from C++ GUI applications (clients) using a Named Pipe very infrequently; it could be days to weeks before a message is received. In my testing I noticed that instead of blocking for data to come in, it just continually checks and prints newlines. It does receive the test message but I had to use the debugger in Visual Studio to verify.
Is there a way to get the C# portion to block until there is actually data to be received?
--C# Code:
var client = new NamedPipeServerStream("PipeTest");
client.WaitForConnection();
StreamReader reader = new StreamReader(client);
while (true)
{
Console.WriteLine(reader.ReadLine());
}
--C++ Code:
DWORD written;
INT error_code;
CHAR buffer[1024];
LPCWSTR pipe_name = L"\\\\.\\pipe\\PipeTest";
LRESULT result;
WaitNamedPipe(pipe_name, NMPWAIT_WAIT_FOREVER);
HANDLE hpipe = CreateFile(pipe_name,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
error_code = GetLastError();
sprintf_s(buffer,"Sending Test Message");
WriteFile(hpipe,buffer,strlen(buffer),&written,NULL);
result = GetLastError();
fprintf(stdout,"Pipe: %d Write: %d Written: %d",error_code,result,written);
DisconnectNamedPipe(hpipe);
CloseHandle(hpipe);
std::cin.get();
[ANSWER]
--C# Code(server) with corrected names:
var server = new NamedPipeServerStream("PipeTest");
while (true)
{
server.WaitForConnection();
StreamReader reader = new StreamReader(server);
Console.WriteLine(reader.ReadLine());
server.Disconnect();
}
For this code I'll only need to capture one line worth of data, #The Shooter was correct but you'll need to add server.Disconnect() in order to read again. I found this from the C documentation and the same principle works in C# apparently.
The server process must call DisconnectNamedPipe to disconnect a pipe handle from its previous client before the handle can be connected to another client by using the ConnectNamedPipe function.
The client end is disconnecting the pipe, so the server sees the end of the input stream immediately after the test message is received.
The documentation for StreamReader.ReadLine() says:
The next line from the input stream, or null if the end of the input stream is reached.
So ReadLine is returning null; what does Console.WriteLine(String) do in that case?
If value is null, only the line terminator is written to the standard output stream.
QED. The behaviour you're seeing is exactly as expected.
You need to check the value returned from ReadLine and deal with null appropriately. In this case you presumably want to wait for another connection.
Instead of:
var client = new NamedPipeServerStream("PipeTest");
client.WaitForConnection();
StreamReader reader = new StreamReader(client);
while (true)
{
Console.WriteLine(reader.ReadLine());
}
Try this:
var client = new NamedPipeServerStream("PipeTest");
while (true)
{
client.WaitForConnection();
StreamReader reader = new StreamReader(client);
Console.WriteLine(reader.ReadLine());
}

C# HttpListener resets connection

I am building a system with on one side an Android app, that uses an HTTPURLConnection to communicate with the other side, which is a C# HttpListener. Over this channel they communicate with XML data.
This works very well, except for some larger data. When I try to communicate that, I see the XML from Android arrives the C# application en the C# application does respond. However, before the data arrives the Android, I get a "Connection reset by peer." exception.
This is the Android code:
URL url = new URL(urlString);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
connection.setDoOutput(true);
connection.setFixedLengthStreamingMode(tel.length());
connection.setReadTimeout(30000);
// write our telegram...
OutputStream output = new BufferedOutputStream(connection.getOutputStream());
output.write(tel.getBytes());
output.flush();
and here is the reply read:
InputStream input = new BufferedInputStream(connection.getInputStream());
if (connection.getResponseCode() == HttpStatus.SC_OK) {
String r = null;
byte cbuf[] = new byte[connection.getContentLength()];
if (input.read(cbuf, 0, connection.getContentLength()) != -1) {
r = new String(cbuf);
}
reply = Telegram.fromString(r);
} else {
throw new ProtocolException("HTTP Error code: "+connection.getResponseCode());
}
and this is the C# code:
httpListener = new HttpListener();
httpListener.Prefixes.Add(String.Format("http://*:{0}/", port);
httpListener.Start();
Turns out, the connection.getContentLength() does not always match the number of bytes read in the input.read(), so the read call waits (and eventually, the server resets as it is done sending I guess).
To fix, I rewrote the receiving side to:
int bufs = 256, read;
ByteArrayOutputStream cbuf = new ByteArrayOutputStream(bufs);
byte[] tempbuf = new byte[bufs];
while ((read = input.read(tempbuf, 0, bufs)) != -1) {
Log.d(PocketApplication.TAG, "Read "+read+" bytes.");
cbuf.write(tempbuf);
}
and it works fine now. Making the size of bufs too large causes it to fail again (e.g. with 1024, the same problem occurs).

Categories