Reputation: 2900
Have a simple named pipes server:
static void Main(string[] args)
{
StartServer();
Console.Read();
}
static void StartServer()
{
Task.Factory.StartNew(() =>
{
var server = new NamedPipeServerStream("TestPipes");
server.WaitForConnection();
StreamReader reader = new StreamReader(server);
StreamWriter writer = new StreamWriter(server);
while (true)
{
var line = reader.ReadLine();
if (line == "Y")
{
for (int i = 0; i < 5; i++)
writer.WriteLine(i.ToString());
writer.Flush();
}
if (line=="N")
{
for (int i = 10; i < 15; i++)
writer.WriteLine(i.ToString());
writer.Flush();
}
}
});
}
and very simple client:
static void Main(string[] args)
{
//Client
var client = new NamedPipeClientStream(Environment.MachineName, "TestPipes");
client.Connect();
Console.WriteLine($"Connection esteblished at {DateTime.Now}, you may continue");
StreamReader reader = new StreamReader(client);
StreamWriter writer = new StreamWriter(client);
while (true)
{
string input = Console.ReadLine();
if (String.IsNullOrEmpty(input)) continue;
writer.WriteLine(input);
writer.Flush();
string serverString;
while (reader.Peek() >= 0)
{
serverString = reader.ReadLine();
Console.WriteLine(serverString);
}
}
}
but for some reason only first command is being completed. for example if I enter 'Y' getting output 'Y' and then when 'N' is entered nothing comes from the server. Need to make it work continuously. Thank you.
Upvotes: 2
Views: 305
Reputation: 101643
Using Peek
is very rarely good idea, and it's not a good idea here either. For example, try to simulate server delay like this:
var line = reader.ReadLine();
if (line == "Y") {
for (int i = 0; i < 5; i++) {
writer.WriteLine(i.ToString());
writer.Flush();
// delay
Thread.Sleep(100);
}
}
And you will see that your code with Peek
(including accepted answer) will fail and just read one line (and on subsequent inputs, like "N", will again display nothing, just like it does now). So your code with Peek
is not reliable and will surprisingly fail at the most inappropriate moment.
Instead, let server explicitly mark end of data it sends. For example, with empty line:
if (line == "Y") {
for (int i = 0; i < 5; i++) {
writer.WriteLine(i.ToString());
writer.Flush();
// simulate delay
Thread.Sleep(100);
}
// empty line
writer.WriteLine();
writer.Flush();
}
And on client:
string serverString;
while (true)
{
serverString = reader.ReadLine();
if (!String.IsNullOrWhiteSpace(serverString))
Console.WriteLine(serverString);
else break;
};
This code will work reliably
Moving StreamReader
to inner while loop as other answer suggests is also not needed, it looks like it "fixes" your code, but really it doesn't fix anything and just puts your problem under the carpet.
Upvotes: 0
Reputation: 7423
That's because in your client you're defining StreamReader reader = new StreamReader(client);
outside of the while loop, so on the first iteration when the reader hits the last line, the underlying stream never gets reset, so reader.Peek() >= 0
yields false for subsequent calls.
Move the declaration of the client reader object inside the while loop:
var client = new NamedPipeClientStream(Environment.MachineName, "TestPipes");
client.Connect();
Console.WriteLine($"Connection esteblished at {DateTime.Now}, you may continue");
StreamWriter writer = new StreamWriter(client);
while (true)
{
StreamReader reader = new StreamReader(client);
string input = Console.ReadLine();
if (String.IsNullOrEmpty(input)) continue;
writer.WriteLine(input);
writer.Flush();
string serverString;
while (reader.Peek() >= 0)
{
serverString = reader.ReadLine();
Console.WriteLine(serverString);
}
}
Upvotes: 1