我创建了多个服务器。每个服务器都必须将一些数据发送到自己的客户端。我正在使用TCP / IP协议。为了防止客户端断开连接导致的任何数据丢失,我使用文本文件作为缓冲区。所以在程序中,每个服务器都有一个线程,它不断检查客户端是否连接。如果已连接,则从缓冲区读取并将其发送到客户端。每当必须将一些新数据发送到客户端时,我首先检查客户端是否已连接。如果客户端未连接,则我将数据写入相同的缓冲区文本文件。我面临的问题是,当线程从中读取文件时,我无法写入文件。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WindowsFormsApplication1
{
public class TcpIp
{
public int machinePort;
public static int port1 = 1024;
public static int count = 0;
public string bufferName;
FileStream buffer;
Socket client;
public IPAddress localIp;
public TcpListener sender;
StreamReader reader ;
FileStream iStream;
//this.get
public TcpIp(string id)
{
this.machinePort = port1 + count;
while (!isAvailable(this.machinePort))
{
count++;
this.machinePort = port1 + count;
}
this.bufferName = WindowsFormsApplication1.Program.path + "machine_" + id + ".txt";
buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
localIp = IPAddress.Parse(WindowsFormsApplication1.Program.ip);
sender = new TcpListener(localIp, this.machinePort);
// this.oStream = new FileStream(this.bufferName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
//this.iStream = new FileStream(this.bufferName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// reader = new StreamReader(this.iStream);
}
bool isAvailable(int port)
{
bool isAvailable = true;
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
{
if (tcpi.LocalEndPoint.Port == port)
{
isAvailable = false;
break;
}
}
return isAvailable;
}
public void createServer()
{
this.sender.Start();
string line;
reader = new StreamReader(buffer);
//client = sender.AcceptSocket();
while (true)
{
line = reader.ReadLine();
if (!connected())
{
client = sender.AcceptSocket();
}
while (reader.EndOfStream && line != null)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(line);
client.Send(bytes, 0, bytes.Length, SocketFlags.None);
line = reader.ReadLine();
}
// iStream.Flush();
Thread.Sleep(3000);
//reader = new StreamReader(iStream);
}
}
public void writeToClient(string data)
{
if (connected())
{
//send data to client
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
//System.Buffer.BlockCopy(data.ToCharArray(), 0, bytes, 0, bytes.Length);
this.client.Send(bytes, 0, bytes.Length, SocketFlags.None);
}
else
{
//write to file
while (true)
{
try
{
StreamWriter sw = File.AppendText(this.bufferName);
sw.WriteLine(data);
sw.Close();
break;
}
catch (Exception ex)
{
Console.WriteLine("WaitForFile {0} failed to get an exclusive lock: "+ex.Message );
// Wait for the lock to be released
System.Threading.Thread.Sleep(500);
}
}
}
}
bool connected()
{
if (client == null)
return false;
else
return client.Connected;
}
}
}
任何启蒙都会受到赞赏。谢谢:))
答案 0 :(得分:2)
实际问题是您混淆了对文件的访问权。
您可以buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
打开一个流,以便从打开的流中创建StreamReader
,以便reader = new StreamReader(buffer);
稍后阅读。
OTOH,您希望获得StreamWriter
StreamWriter sw = File.AppendText(this.bufferName);
来写文件{{1}}。这会尝试再次打开文件,因为文件共享模式不匹配而失败。
所以你需要通过相同的"句柄来访问文件进行写作和阅读。 (这里是FileStream)。此外,不要忘记通过某种锁定机制序列化访问,以使其成为线程安全的。否则,您将收到损坏的数据。您可能需要维护读/写指针(Stream.Position)。
答案 1 :(得分:1)
您无法同时从同一文本文件中读取和写入。
如果您真的想使用文本文件,为什么不使用其中的两个: 一个读取,一个读写。 一旦读取文件为空 - >读取文件是您的新写入文件,反之亦然。
答案 2 :(得分:0)
这听起来很合理,2个线程不可能同时访问文件,因为该文件正在使用中。
想象一下,即使有可能,你也会有一些非常奇怪的行为。
为什么不使用lock()来确保在给定时间只有一个线程可以访问该文件?
使用异步编程,您无需等到锁定被释放后再继续执行程序。
答案 3 :(得分:0)
你必须像这样创建线程
Thread thread = new Thread(yourMethod());
当你有多个线程时,你需要的是ReaderWriterLockSlim。这是link。
它允许您通过多个线程读取文件,但使用一个Thread写入文件。我认为这将解决您的问题。