Hello I am having a strange error with using pipes to communicate between two process. In short everything is working fine with the program except that the client side never closes the stream, meaning the server's streamReader.readLine never returns null, causing the sever process to never terminate. I'm convinced this is a simple issue but I and struggling to find a answer. Here is some relevant code:
Server Side:
using (StreamReader sr = new StreamReader(clientServer))
{
// Display the read text to the console
string temp;
int count = 0;
while ((temp = sr.ReadLine()) != null)
{
if (count == 0)
{
Console.WriteLine("==========Parent Process found text:like==========");
}
Console.WriteLine(temp);
count++;
}
Console.WriteLine("out of while loop");
}
Client Project:
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
class PipeClient
{
static void Main(string[] args)
{
try
{
if (args.Length < 3)
{
Console.WriteLine("Invalid number of commandline arguments");
}
else
{
List<string> inputList = new List<string>();
List<string> foundMatchList = new List<string>();
using (PipeStream pipeClientIn =
new AnonymousPipeClientStream(PipeDirection.In, args[0]))
{
using (StreamReader sr = new StreamReader(pipeClientIn))
{
// Display the read text to the console
string temp;
int count = 0;
while ((temp = sr.ReadLine()) != null)
{
if (count == 0)
{
Console.WriteLine("==========Client Process Read Text:==========");
}
Console.WriteLine(temp);
inputList.Add(temp);
count++;
}
foreach (var curtString in inputList)
{
if (curtString.Contains(args[2]))
{
foundMatchList.Add(curtString);
}
}
}
//Console.WriteLine("released sr");
}
// Console.WriteLine("released pipeClientIn");
using (PipeStream pipeClientOut =
new AnonymousPipeClientStream(PipeDirection.Out, args[1]))
{
using (StreamWriter sw = new StreamWriter(pipeClientOut))
{
sw.AutoFlush = true;
foreach (var match in foundMatchList)
{
sw.WriteLine(match);
}
}
}
//Console.WriteLine("released pipeClientOut");
}
}
catch (Exception e)
{
/* if (args.Length == 0)
Console.WriteLine("no arguments");
foreach(String s in args)
{
Console.Write("{0} ", s);
}*/
Console.WriteLine(e.Message);
}
}
}
I've tested and can confirm that the client process terminates.
I attempted to manually flush and close the Client StreamWriter but this did not work.
My overall question is: Why am I never seeing the the "out of while loop" message? And how can fix my client so that it will end the stream?
Did you call clientServer.DisposeLocalCopyOfClientHandle()?
from msdn
The DisposeLocalCopyOfClientHandle method should be called after the
client handle has been passed to the client. If this method is not
called, the AnonymousPipeServerStream object will not receive notice
when the client disposes of its PipeStream object.
hope this helps
Related
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.
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);
}
}
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.
I'm writing a program which splits a CSV file in four almost-equal parts.
I'm using a 2000-lines CSV input file as example, and when reviewing the output files, there are lines missing in the first file, and also there are uncomplete lines which makes no sense, since I'm writing line by line. Here the code:
using System.IO;
using System;
class MainClass {
public static void Main(string[] args){
string line;
int linesNumber = 0, linesEach = 0, cont = 0;
StreamReader r = new StreamReader("in.csv");
StreamWriter w1 = new StreamWriter("out-1.csv");
StreamWriter w2 = new StreamWriter("out-2.csv");
StreamWriter w3 = new StreamWriter("out-3.csv");
StreamWriter w4 = new StreamWriter("out-4.csv");
while((line = r.ReadLine()) != null)
++linesNumber;
linesEach = linesNumber / 4;
r.DiscardBufferedData();
r.BaseStream.Seek(0, SeekOrigin.Begin);
r.BaseStream.Position = 0;
while((line = r.ReadLine()) != null){
++cont;
if(cont == 1){
//fisrt line must be skipped
continue;
}
if(cont < linesEach){
Console.WriteLine(line);
w1.WriteLine(line);
}
else if(cont < (linesEach*2)){
w2.WriteLine(line);
}
else if(cont < (linesEach*3)){
w3.WriteLine(line);
}
else{
w4.WriteLine(line);
}
}
}
}
Why is the writing part doing wrong? How can I fix it?
Thank you all for your help.
You could simplify your approach by using a Partitioner and some LINQ. It also has the benefit of only having two file handles open at once, instead of 1 for each output file plus the original input file.
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
namespace FileSplitter
{
internal static class Program
{
internal static void Main(string[] args)
{
var input = File.ReadLines("in.csv").Skip(1);
var partitioner = Partitioner.Create(input);
var partitions = partitioner.GetPartitions(4);
for (int i = 0; i < partitions.Count; i++)
{
var enumerator = partitions[i];
using (var stream = File.OpenWrite($"out-{i + 1}.csv"))
{
using (var writer = new StreamWriter(stream))
{
while (enumerator.MoveNext())
{
writer.WriteLine(enumerator.Current);
}
}
}
}
}
}
}
This is not direct answer to your question, just an alternative.
Linq can be used to create shorter codes
int inx = 0;
var fInfo = new FileInfo(filename);
var lines = File.ReadAllLines(fInfo.FullName);
foreach (var groups in lines.GroupBy(x => inx++ / (lines.Length / 4)))
{
var newFileName = $"{fInfo.DirectoryName}\\{fInfo.Name}_{groups.Key}{fInfo.Extension}";
File.WriteAllLines(newFileName, groups);
}
Thank you all for your answers.
The problem is, as Jegan and spender suggested, that the StreamWriter needs to be wrapped in the using clause. That said, problem solved.
Trying to check if the file is empty or not, and then write something like "the text is empty" into the document.
But whenever I do get the
the process cannot access the file because it is being used by another process
even though I'm closing the file after the write.
What am I missing here?
StreamWriter myWriter1 = new StreamWriter(resultpath);
List<string> a = File.ReadAllLines(path).ToList();
List<string> b = File.ReadAllLines(newPath).ToList();
foreach (string s in a)
{
Console.WriteLine(s);
if (!b.Contains(s))
{
myWriter1.WriteLine(s);
myWriter1.Close();
}
else
{
continue;
}
}
string[] resultfile = File.ReadAllLines(resultpath);
if (resultfile == null || resultfile.Length == 0)
{
myWriter1.WriteLine("Der er ikke nogen udmeldinger idag", true);
}
myWriter1.Close();
You can close & dispose file writer after writing to it in the loop and re-create it when you neet to write to the same file again.
Also note it is better to wrap it into using statement to ensure it wil be closed and set free unmanaged resources automatically (so you don't need to close it in the loop again and again).
List<string> a = File.ReadAllLines(path).ToList();
List<string> b = File.ReadAllLines(newPath).ToList();
using (var myWriter1 = new StreamWriter(resultpath, false))
{
foreach (string s in a)
{
Console.WriteLine(s);
if (!b.Contains(s))
myWriter1.WriteLine(s);
}
}
string[] resultfile = File.ReadAllLines(resultpath);
if (resultfile == null || resultfile.Length == 0)
{
using (var myWriter1 = new StreamWriter(resultpath, true))
{
myWriter1.WriteLine("Der er ikke nogen udmeldinger idag", true);
}
}
Try this code. You were closing the StreamWriter on each line that is in the 2 analized files,but if there is no coincidence, you never close it.
using (var myWriter1 = new StreamWriter(resultpath, true))
{
List<string> a = File.ReadAllLines(path).ToList();
List<string> b = File.ReadAllLines(newPath).ToList();
int coincidences=0;
foreach (string s in a)
{
Console.WriteLine(s);
if (!b.Contains(s))
{
myWriter1.WriteLine(s);
coincidences++;
}
}
if (coincidences == 0)
{
myWriter1.WriteLine("Der er ikke nogen udmeldinger idag", true);
}
}
Also,note that for IDisposable objects it's better to enclose it in a using clause,as it disposes all the resources when finished.
When the code is RUN it has to ping the websites I specify 4 times each and then write the results in a .csv file. But I'm keep getting a TIMEOUT error. Can anyone tell me why? I tried so many different things and noting is working so far. Please help me out.
static void Main(string[] args)
{
List<string> lstWebSites = new List<string>();
lstWebSites.Add("www.yahoo.com");
lstWebSites.Add("www.att.com");
lstWebSites.Add("www.verizon");
string filename = #"PingLog.csv";
{
using (var writer = new StreamWriter(filename, true))
{
foreach(string website in lstWebSites)
{
writer.WriteLine(website);
try
{
Ping myPing = new Ping();
PingReply reply = myPing.Send(website, 1000);
if (reply != null)
{
Console.WriteLine("{0}, {1}", reply.Address, reply.RoundtripTime);
}
}
catch
{
Console.WriteLine.("ERROR: You have some TIMEOUT issue");
}
}
}
}
}
}
}
Here's a working example. I added some comments where you had syntax errors or where I made adjustments to your original code.
// Missing quotes, should probably be a full file path
string filename = #"C:\temp\PingLog.csv";
// You had an extra opening brace here
// Open a file for writing using the filename, and a flag that means whether to append
using (var writer = new StreamWriter(filename, false))
{
// Write a CSV header
writer.WriteLine("Status, Time, Address");
try
{
Ping myPing = new Ping();
PingReply reply = myPing.Send("www.yahoo.com", 1000);
if (reply != null)
{
// Use the overload of WriteLine that accepts string format and arguments
writer.WriteLine("{0}, {1}, {2}", reply.Status, reply.RoundtripTime, reply.Address);
}
}
catch
{
// You had a syntax error here
Console.WriteLine("ERROR: You have some TIMEOUT issue");
}
}
Ok I have most of this figured out. Thank you all so much for helping me.
Although, I still need this to ping at least three more websites and give me 4 ping results per website.
So if someone could please, please just help me out a little bit more.
Here is what I have and this so far it works:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace Ping Application
{
class Program
{
static void Main(string[] args)
{
string filename = #"PingLog.csv";
{
using (var writer = new StreamWriter(filename, true))
{
writer.WriteLine("www.yahoo.com", Time in MilliSeconds);
try
{
Ping myPing = new Ping();
PingReply reply = myPing.Send("www.yahoo.com", 1000);
if (reply != null)
{
Console.WriteLine("{0}, {1}, {2}", reply.Address, reply.RoundtripTime, reply.RoundtripTime);
}
}
catch
{
Console.WriteLine.("ERROR: You have some TIMEOUT issue");
}
}
}
}
}
}
Description
Download multiple files using webclient's DownloadFileAsync and utilizing a text file for URL input for download.
Problem
The approach that I have used won't download files at all. Just runs and does nothing. It fills the list array then quits the program without downloading a single file. I have googled for solutions but come up shorthanded. Then attempted to search for a solution in the database here with same results. Any help is appreciated.
Questions
Why does this approach not work?
What can I do to improve this and learn from this.
Code
DownloadClass.cs
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
class DownloadClass
{
public struct download
{
public static string URL { get; set; }
public static string file { get; set; }
public static string[] link;
public static int downloadcount;
}
public static List<string> list = new List<string>();
public static WebClient wc = new WebClient();
public static void Download()
{
int count = 0;
download.URL = list[0];
Uri URI = new Uri(download.URL);
UriBuilder uri = new UriBuilder(URI);
download.link = uri.Path.ToLower().Split(new char[] { '/' });
count = 0;
// Find file
foreach (string abs in download.link)
{
count++;
if (abs.ToLower().Contains(".html") || abs.ToLower().Contains(".exe") || abs.ToLower().Contains(".txt"))
{
try
{
download.file = download.link[count];
wc.Proxy = null;
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
wc.DownloadFileAsync(URI, Application.StartupPath + "\\" + download.file);
break;
}
catch (Exception)
{ }
}
}
}
public static void BeginDownload()
{
new Thread(Download).Start();
}
public static void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
int count = 0;
download.downloadcount++;
download.URL = list[0];
Uri URI = new Uri(download.URL);
UriBuilder uri = new UriBuilder(URI);
download.link = uri.Path.ToLower().Split(new char[] { '/' });
count = 0;
// Find file
foreach (string abs in download.link)
{
count++;
if (abs.ToLower().Contains(".html") || abs.ToLower().Contains(".exe") || abs.ToLower().Contains(".txt"))
{
try
{
download.file = download.link[count];
}
catch (Exception)
{ }
}
}
list.RemoveAt(0);
if (list.Count > 0)
{
wc.DownloadFileAsync(URI, list[download.downloadcount], Application.StartupPath + "\\" + download.file);
}
else
{
Console.WriteLine("Downloading is done.");
Environment.Exit(0);
}
}
}
}
Program.cs (Main Class)
using System;
using System.IO;
using System.Collections.Generic;
using System.Windows.Forms;
namespace ThreadTest
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: {0} <download txtfile>", Environment.GetCommandLineArgs()[0]);
Environment.Exit(0);
}
int counter = 0;
string line;
string format = string.Format("{0}\\{1}", Application.StartupPath, args[0]);
// Read the file line by line.
using(StreamReader file = new StreamReader(format))
{
while ((line = file.ReadLine())!= null)
{
// Store urls in a list.
DownloadClass.list.Add(line);
counter++;
}
}
DownloadClass.BeginDownload();
}
}
}
Besides being bad design there are lots of issues that lead to your code not (or nor correctly working).
You need to make sure that you application lives while it downloads something. Your current app quits right away (you have to wait for the downloading to complete in your main).
You application may download the same file multiple times but not download others at all (You need to completely lock object when they are used in an async=multithreading way like here when accessing static objects) BTW: Don't use static objects at all to avoid that in the first place.
Even if 2 is corrected it may still download the same file multiple times into the same filename and thus fail.
As long as you have no knowledge about multithreading I'd recommend you use the synchoneous methods to avoid all those problems.