简体   繁体   English

共享网络文件以进行读写

[英]Sharing network files for writing and reading

I have client-server application developed in C#.NET 3.5. 我在C#.NET 3.5中开发了客户端服务器应用程序。 This application uses 3 programs to complete the required work. 该应用程序使用3个程序来完成所需的工作。 Process A(Server) and Process B(remote launcher) are developed in .NET and Process C is a third party console application whose development language is not known. 进程A(服务器)和进程B(远程启动器)是在.NET中开发的,进程C是第三方控制台应用程序,其开发语言未知。 Using the Administrative credentials of remote computer, Process A copies Process B on that and schedules Process B as task on remote computer. 使用远程计算机的管理凭据,进程A在其上复制进程B,并将进程B安排为远程计算机上的任务。 After this, Process B starts by task scheduler and it creates log.txt file to log the messages. 此后,进程B由任务计划程序启动,并创建log.txt文件来记录消息。 Then Process B starts Process C using Process.Start() semantics and redirects its standard output and error to write into log.txt file. 然后,进程B使用Process.Start()语义启动进程C,并重定向其standard output and error以写入log.txt文件。 Process A uses Process.GetProcesses(remotecomputername) semantics to monitor whether Process C is still running on remote computer. 进程A使用Process.GetProcesses(remotecomputername)语义来监视进程C是否仍在远程计算机上运行。 Process A is also reading the log.txt file using network share read like \\\\RemoteComputerName\\C$\\RemoteDir\\log.txt and displaying the messages on its window. 进程A还使用网络共享读取\\\\RemoteComputerName\\C$\\RemoteDir\\log.txt读取log.txt文件,并在其窗口中显示消息。

My issue is, all the output and error are not getting logged on log.txt . 我的问题是,所有输出和错误都未登录到log.txt And Process A is not able to read correctly from log.txt . 并且进程A无法从log.txt正确读取。 If the output/error logged using DebugView they are getting logged correctly.Is this synchronization/access rights issue? 如果使用DebugView记录了输出/错误,则说明它们已正确记录。是否存在同步/访问权限问题? How to get rid of it? 如何摆脱它? Any pointers/hints will be truly valuable. 任何指针/提示将是真正有价值的。 Unable to share full code due to restrictions. 由于限制,无法共享完整代码。

Sample code given below 下面给出示例代码

Process A 工序A

//Below method is called every 2 seconds from Server to read new messages.
//path passed as `\\RemoteComputerName\C$\RemoteDir\log.txt`
private void ReadRemoteLog(string path)
{
    try
    {
        string[] lines = File.ReadAllLines(path);
        while (RemoteLogPosition < lines.LongLength)
        {
            string msg = lines[RemoteLogPosition].Trim();
            if (!string.IsNullOrEmpty(msg))
            {
                Trace.WriteLine("# " +msg); //Writing on DebugView
                OnProgressChanged(msg);
            }
            RemoteLogPosition++; //This is global variable to keep track of last read position.
        }      
    }   
}

Process B's code for starting Process C 流程B的代码,用于启动流程C

ProcessStartInfo ps = new ProcessStartInfo();
ps.UseShellExecute = false;
ps.FileName = <Path to process C>;
ps.Arguments = <Commandline args to Process C>;
ps.WorkingDirectory = @"C:\RemoteDir";
ps.RedirectStandardError = true;
ps.RedirectStandardOutput = true;

Process p = new Process();
p.StartInfo = ps;

p.OutputDataReceived += (s, e) => { WriteLog(e.Data.Trim());};
p.ErrorDataReceived += (s, e) => { WriteLog(e.Data.Trim()); };
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
WriteLog("Process Started - "+ps.FileName + ps.Arguments);
p.WaitForExit();

Process B's WriteLog Method - 进程B的WriteLog方法-

private void WriteLog(string message)
{
    using (FileStream fs = new FileStream(@"C:\\RemoteDir\log.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Inheritable))
    using(StreamWriter sw = new StreamWriter(fs))
    {
        sw.WriteLine("#" + message);
    }
}

Remember File get exclusive lock when its getting written. 请记住,文件写入时会获得排他锁。 So if two threads are writing at same time one of them will get into exception. 因此,如果两个线程同时写入,则其中一个将陷入异常。 Reading is not a problem. 阅读不是问题。 The easy solution is make multiple log file or use database. 简单的解决方案是制作多个日志文件或使用数据库。 The other way is keep accumulating message and write once in an hour or when message are up to 100 . 另一种方法是保持消息累积并在一个小时内或消息达到100条时写入一次。 Make list of string 制作字符串列表

List<string> messagelst= new List<string>();
private void WriteLog(string message)
{


        messagelst.Add("New York");
        messagelst.Add("Mumbai");
        messagelst.Add("Berlin");
        messagelst.Add("Istanbul");
if(messagelst.length==100){
string message= string.Join(",", messagelst.ToArray());

    using (FileStream fs = new FileStream(@"C:\\RemoteDir\log.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Inheritable))
    using(StreamWriter sw = new StreamWriter(fs))
    {
        sw.WriteLine("#" + message);
    }

messagelst= new List<string>();

}
}

The other way is write async. 另一种方法是写异步。 You may loose sequence . 您可能会松动顺序。

static Task ProcessWrite()
{
    string filePath = @"c:\temp2\temp2.txt";
    string text = "Hello World\r\n";

    return WriteTextAsync(filePath, text);
}

static async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);

    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize: 4096, useAsync: true))
    {
        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    };
}

Short answer: File.ReadAllLines will not let the other process write to the file. 简短的答案: File.ReadAllLines将不允许其他进程写入文件。 Related SO question which has some workarounds: File.ReadLines without locking it? 相关的SO问题有一些解决方法: File.ReadLines是否未锁定?

The fact that ReadAllLines is opening the file with FileShare.Read can be found by looking at the .Net reference source code: https://referencesource.microsoft.com/#mscorlib/system/io/file.cs,5150c565446cd5fd 这一事实ReadAllLines正在打开与该文件FileShare.Read可以通过查看.NET参考的源代码中找到: https://referencesource.microsoft.com/#mscorlib/system/io/file.cs,5150c565446cd5fd

By tracing the calls, it would eventually reach: 通过跟踪呼叫,最终将达到:

Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost);

The FileShare.Read says FileShare.Read

Allows subsequent opening of the file for reading. 允许随后打开文件进行读取。 If this flag is not specified, any request to open the file for reading (by this process or another process) will fail until the file is closed. 如果未指定此标志,则打开文件以进行读取的任何请求(通过此过程或其他过程)都将失败,直到关闭文件为止。

Even though ReadAllLines will close the file, during the process of reading, the file is not available for other process to write to. 即使ReadAllLines将关闭文件,在读取过程中,该文件也不可供其他进程写入。

You essentially, need to open the file with FileShare.ReadWrite (in your Process A) to allow the other process (your Process C) to continue to write this file. 本质上,您需要使用FileShare.ReadWrite (在进程A中)打开文件,以允许另一个进程(您的进程C)继续写入此文件。

You can try using an object as a lock while writing to file: 您可以在写入文件时尝试将对象用作锁:

private static object fileLock = new Object();

Now in your WriteLog Method: you can use lock(fileLock) {} use using to dispose off the stream. 现在在WriteLog方法中:您可以使用lock(fileLock) {}使用using来处理流。

Also you can have a look at EventWaitHandle . 您也可以看看EventWaitHandle It allows to create an instance of wait handle for every process. 它允许为每个进程创建一个等待句柄的实例。

var wait = new EventWaitHandle(true, EventResetMode.AutoReset, "Common_to_all_process");

Then after first process has finished, it can pass it on to the next process by signalling: 然后,在第一个进程完成后,可以通过发出信号将其传递到下一个进程:

wait.WaitOne();
/* write to the file*/
wait.Set();

One can use a GUID for “Common_to_all_process”. 可以将GUID用于“ Common_to_all_process”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM