Hey Guys i am starting an EPP client and it only returns the greeting from the server, even when i try send my login command.
here is my code, what is wrong with it?
using (var _tcpClient = new TcpClient(_endpoint.Host, _endpoint.Port))
{
using (var sslStream = new SslStream(_tcpClient.GetStream(), false, ValidateServerCertificate))
{
sslStream.AuthenticateAsClient(_endpoint.Host);
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(requestData);
xdoc.Save("C:/request.xml");
string data = xdoc.InnerXml;
byte[] bytedata = Encoding.UTF8.GetBytes(data);
//Get the request stream.
sslStream.Write(bytedata, 0, bytedata.Length);
// Write the data to the request stream.
sslStream.Flush();
var response = ReadMessage(sslStream);
XResponse = XDocument.Parse(response);
XResponse.Save("C:/response.xml");
}
}
return XResponse;
}
private string ReadMessage(SslStream sslStream)
{
// The first four bytes will be the the content length as a network order (big-endian) 32-bit number.
var lengthBytes = new byte[4];
sslStream.Read(lengthBytes, 0, 4);
Array.Reverse(lengthBytes);
var length = BitConverter.ToInt32(lengthBytes, 0) - 4;
// Create a byte array of the correct size for the response.
var messageBytes = new byte[length];
var returned = 0;
while (returned != length)
{
returned += sslStream.Read(messageBytes, 0, length);
}
return Encoding.UTF8.GetString(messageBytes);
}
Even if i do not write anything with the ssl stream it still returns the greeting.
if you guys could point me in the right direction it would be greatly appreciated.
Each time you send any command or open a connection, you must read and flush the response. I fell into this trap when developing my EPP client.
Connect. Read response (you get the greeting)
Send Login command. Read response (you get the login response)
Send Command. Read Response.
Send Disconnect. Read Response.
I imagine you're connecting, then sending a login command and wondering why the response you just got was the greeting. You missed a step. :)
Upon connection the server will typically reply with a greeting.
Read the greeting response upon connection. Then you can send commands and receive responses as normal.
Related
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?
You can find similar code examples in many places on the internet:
var apnsHost = "gateway.sandbox.push.apple.com";
var apnsPort = 2195;
var timeout = 3000;
using(TcpClient client = new TcpClient(AddressFamily.InterNetwork))
{
await client.ConnectAsync(apnsHost, apnsPort);
using (SslStream sslStream = new SslStream(client.GetStream(), false, _certificateValidationCallback, null))
{
try
{
sslStream.AuthenticateAsClient(apnsHost, _certificateCollection, System.Security.Authentication.SslProtocols.Tls, true);
} catch {
throw;
}
MemoryStream memoryStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(memoryStream);
byte[] binaryToken = StringToByteArray(deviceToken);
writer.Write((byte)0); // The command
writer.Write((byte)0); // The first byte of the deviceId length (bit-endian first byte)
writer.Write((byte)32); // The deviceId length (big-endian second byte)
writer.Write(binaryToken);
byte[] bytesPayload = Encoding.UTF8.GetBytes(payload);
writer.Write((byte)0);
writer.Write((byte)bytesPayload.Length);
writer.Write(bytesPayload);
writer.Flush();
byte[] array = memoryStream.ToArray();
sslStream.Write(array);
sslStream.Flush();
}
}
While I understand that this code shakes hands with APNS, establishes a TLS connection and writes appropriate request content, I don't really understand where in this code I can specify additional Headers!
Apple describes here various headers that can be specified, and I am interested in specifying apns-expiration and apns-priority but I just can't figure out where and what kind of code can I fit in here to achieve my goal?
I think when you have the TCP Client connect (not connectAsync) you can specify an IPEndPoint object and use that do set the headers.
TCP Client Connect: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.connect?view=netframework-4.7.2#System_Net_Sockets_TcpClient_Connect_System_Net_IPEndPoint_
IPEndPoint: https://learn.microsoft.com/en-us/dotnet/api/system.net.ipendpoint?view=netframework-4.7.2
I've never tried sending a post like that so not sure what would be the JSON for your request.
I built an app which receiving and sending data to server by the code below, and I noticed It's adding some chars to the string I send as MemoryStream when I'm getting the string back. Here's the code and the debugging information:
Client:
while (true)
{
if (stream.DataAvailable)
{
while ((i = stream.Read(ByteBuffer, 0, ByteBuffer.Length)) != 0)
{
ms.Write(ByteBuffer, 0, ByteBuffer.Length);
if (stream.DataAvailable)
continue;
else
break;
}
ToReturn = Encoding.ASCII.GetString(ms.ToArray());
return ToReturn;
}
}
}
Server:
MemoryStream response = new MemoryStream();
response = Protocol.ProcessRequest(dataRecieved, ClientAddr);
#endregion
Console.WriteLine("Trying to send back response." + Encoding.ASCII.GetString(response.ToArray()));
stream.Flush();
response.WriteTo(stream);
I've checked with the debugger and what printed with the console:
the sent information is just fine, for example:
response.Id^Name^Type^SubType^Description^AddedBy^AddedDT^IsSpecial^Amount#1^VGA cable^cable^display^Very old and common display cable.^Aviv^14/01/2019 22:04:34^False^3345#2^HDMI cable^cable^display^newer and better display cable. can pass network, audio and info.^Aviv^14/01/2019 22:05:30^False^4793
but the info received on the other side of the socket (the client) was:
Id^Name^Type^SubType^Description^AddedBy^AddedDT^IsSpecial^Amount#1^VGA cable^cable^display^Very old and common display cable.^Aviv^14/01/2019 22:04:34^False^3345#2^HDMI cable^cable^display^newer and better display cable. can pass network, audio and info.^Aviv^14/01/2019 22:05:30^False^4793alse^4
-with these (alse^4) few chars at the end. can anyone tell me what's the encoding problem? Thanks.
AGAIN: the output from the server is fine
//ms.Write(ByteBuffer, 0, ByteBuffer.Length);
ms.Write(ByteBuffer, 0, i);
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
I'm trying to learn the basics of networking and I've built an echo server from this tutorial. I checked the server with telnet and it works perfect.
Now when I'm using some of the many client samples on the Internet:
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
TcpClient client = new TcpClient(server, port);
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
// Get a client stream for reading and writing.
NetworkStream stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent: {0}", message);
// Receive the TcpServer.response.
// Buffer to store the response bytes.
data = new Byte[256];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
// Close everything.
stream.Close();
client.Close();
It doesn't work very well. If I will comment the stream.Read line, everything works perfect (expect I can't read). I was also trying to accomplish that in a similar way using asynchronous callback method for the read. and then it only works after I terminate the program (the server handles the request)
I suspect that the way I'm reading from the stream cause this block, but I'm too clueless to understand what I'm doing wrong.
The implementation will block until at least one byte of data can be
read, in the event that no data is available.
From MSDN
Your server propably isn't sending you any data.
Edit:
I tested your client and it works perfectly fine. Try it yourself and set the following parameters:
string server = "google.com";
int port = 80;
string message = "GET /\n";
It's definitely your server which has the problem.