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());
}
Related
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 have a simple client/server communication between C++ and C# where the C# program sends a string to the C++.
Sending of a string is done on 3 stages. Send the length of the length of the string--> Send the length of string --> Send the String.
For debugging purposes I have a TextBox called textbox1 on my C# program to print
the sent values using textbox1.AppendText() three times for the three values sent.
Everything was sent and received correctly, When I remove two of the three AppendText() lines from my code it still works but the strange thing is when I remove the third one (Commented as //<--This Line, The C++ server receives 0!
C# Client (Code Snippet):
private void button1_Click(object sender, EventArgs e)
{
try
{
MemoryStream ms;
NetworkStream ns;
TcpClient client;
BinaryWriter br;
byte[] tosend;
string AndroidId = "2468101214161820";
string len = AndroidId.Length.ToString();
string lol = len.Length.ToString();
ms = new MemoryStream();
client = new TcpClient("127.0.0.1", 8888);
ns = client.GetStream();
br = new BinaryWriter(ns);
//****************Send Length Of Length***************
tosend = System.Text.Encoding.ASCII.GetBytes(lol);
br.Write(tosend);
textBox1.AppendText(Encoding.ASCII.GetString(tosend));//<---THIS LINE
//****************Send Length***************
tosend = System.Text.Encoding.ASCII.GetBytes(len);
br.Write(tosend);
//****************Send Length Of Length***************
tosend = System.Text.Encoding.ASCII.GetBytes(AndroidId);
br.Write(tosend);
ns.Close();
client.Close();
}
C++ Server Code Snippet:
//***********Recieve Length Of Length*****************
char* lol_buff0 = new char[1];
int nullpoint= recv(s, lol_buff0, strlen(lol_buff0), 0);
lol_buff0[nullpoint] = '\0';
int lengthoflength = atoi(lol_buff0);
//***********Recieve Length*****************
char* l_buff0 = new char[lengthoflength];
int nullpoint2=recv(s, l_buff0, strlen(l_buff0), 0);
l_buff0[nullpoint2] = '\0';
int length = atoi(l_buff0);
//***********Recieve AndroidID*****************
char* AndroidID = new char[length];
valread0 = recv(s, AndroidID, strlen(AndroidID), 0);
if (valread0 == SOCKET_ERROR)
{
int error_code = WSAGetLastError();
if (error_code == WSAECONNRESET)
{
//Somebody disconnected , get his details and print
printf("Host disconnected unexpectedly , ip %s , port %d \n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
closesocket(s);
client_socket[i] = 0;
}
else
{
printf("recv failed with error code : %d", error_code);
}
}
if (valread0 == 0)
{
//Somebody disconnected , get his details and print
printf("Host disconnected , ip %s , port %d \n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
closesocket(s);
client_socket[i] = 0;
}
else
{
//add null character, if you want to use with printf/puts or other string handling functions
AndroidID[valread0] = '\0';
printf("%s:%d Your Android ID is - %s \n", inet_ntoa(address.sin_addr), ntohs(address.sin_port), AndroidID);
}
I know I can accommodate the TextBox as long as it works but It is so weird and I'd like to know what is the explanation for that. Thanks.
You're assuming that the data will be received in one recv call (or alternatively, that one send corresponds to one receive). That is a false assumption. You need to keep reading until you read length of bytes of data. TCP doesn't have any messaging built in, it only deals with streams.
Adding the line may mean that some small delay is added which makes the receive happen in a single call - it's hard to tell, since you're dealing with something that isn't quite deterministic. Handle TCP properly, and see if the problem persists.
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.
I am trying to learn how to do Named Pipes. So I created a Server and Client in LinqPad.
Here is my Server:
var p = new NamedPipeServerStream("test3", PipeDirection.Out);
p.WaitForConnection();
Console.WriteLine("Connected!");
new StreamWriter(p).WriteLine("Hello!");
p.Flush();
p.WaitForPipeDrain();
p.Close();
Here is my Client:
var p = new NamedPipeClientStream(".", "test3", PipeDirection.In);
p.Connect();
var s = new StreamReader(p).ReadLine();
Console.Write("Message: " + s);
p.Close();
I run the server, and then the client, and I see "Connected!" appear on the server so it is connecting properly. However, the Client always displays Message: with nothing after it, so the data isn't actually travelling from server to client to be displayed. I have already tried swapping pipe directions and having the client send data to the server with the same result.
Why isn't the data being printed out in the screen in this example? What am I missing?
Thanks!
Like L.B said, you must flush the StreamWriter. But employing the using pattern will prevent such mistakes:
using (var p = new NamedPipeServerStream("test3", PipeDirection.Out))
{
p.WaitForConnection();
Console.WriteLine("Connected!");
using (var writer = new StreamWriter(p))
{
writer.WriteLine("Hello!");
writer.Flush();
}
p.WaitForPipeDrain();
p.Close();
}
In the above code, even if Flush() and Close() were omitted, everything would work as intended (since these operations are also performed when an object is disposed). Also, if any exceptions are thrown, everything will still be cleaned up properly.
Change your server code as follows:
StreamWriter wr = new StreamWriter(p);
wr.WriteLine("Hello!\n");
wr.Flush();
your string doesn't get flushed in StreamWriter
With my code I can read a message on the server and write from the client. But I am not being able to write a response from the server and read in the client.
The code on the client
var cli = new TcpClient();
cli.Connect("127.0.0.1", 6800);
string data = String.Empty;
using (var ns = cli.GetStream())
{
using (var sw = new StreamWriter(ns))
{
sw.Write("Hello");
sw.Flush();
//using (var sr = new StreamReader(ns))
//{
// data = sr.ReadToEnd();
//}
}
}
cli.Close();
The code on the server
tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
while (run)
{
var client = tcpListener.AcceptTcpClient();
string data = String.Empty;
using (var ns = client.GetStream())
{
using (var sr = new StreamReader(ns))
{
data = sr.ReadToEnd();
//using (var sw = new StreamWriter(ns))
//{
// sw.WriteLine("Hi");
// sw.Flush();
//}
}
}
client.Close();
}
How can I make the server reply after reading the data and make the client read this data?
Since you are using
TcpClient client = tcpListener.AcceptTcpClient();
, you can write back to the client directly without needing it to self-identify. The code you have will actually work if you use Stream.Read() or .ReadLine() instead of .ReadToEnd(). ReadToEnd() will block forever on a network stream, until the stream is closed. See this answer to a similar question, or from MSDN,
ReadToEnd assumes that the stream
knows when it has reached an end. For
interactive protocols in which the
server sends data only when you ask
for it and does not close the
connection, ReadToEnd might block
indefinitely because it does not reach
an end, and should be avoided.
If you use ReadLine() at one side, you will need to use WriteLine() - not Write() - at the other side. The alternative is to use a loop that calls Stream.Read() until there is nothing left to read. You can see a full example of this for the server side in the AcceptTcpClient() documentation on MSDN. The corresponding client example is in the TcpClient documentation.
Cheesy, inneficient, but does the trick on a one-time throwaway program:
Client: In the stream, include the port and IP address it wishes to receive the response from.
Client: Create a listener for that
port and IP.
Server: Read in the port/IP info and
in turn connect, then send the reply
stream.
However, this is a great place to start, look into Sockets class for proper bi-directional communication.