在1个线程中读取列表,在另一个线程中写入
本文关键字:线程 另一个 读取 1个 列表 | 更新日期: 2023-09-27 18:19:39
我正在尝试创建一个windows服务,当文件到达FTP位置时,它会通过TCP向相关用户发送消息。我已经设置了所有的文件检测部分,但我需要一些消息方面的帮助。
由于将有多个用户同时订阅此服务,因此它需要能够处理多个连接,因此我在服务启动时创建TCPServer服务器,并开始侦听传入连接。当一个连接到达时,代码会将该连接添加到连接列表中。
到目前为止,一切都很好。
当传入文件触发向相关客户端发送消息时,就会出现问题。尝试访问连接列表失败,因为我必须从一个单独的线程进行访问(因为侦听新连接的线程在此期间不能做任何其他事情)。
在调试模式下运行此程序时,我看到New Connection正确地增加了ClientList的计数,但当调试器返回到类以发送消息时,ClientList变量将重置为0,因为我必须创建该类的新实例。任何想法都将不胜感激。
我的代码如下:
namespace WindowsService1
{
class MSGServer
{
TcpListener server = null;
Int32 port = 13000;
IPAddress localAddr;
List<ClientConn> ClientList = new List<ClientConn>();
Byte[] data;
private object l_lock = new object();
public void CreateServer()
{
localAddr = IPAddress.Parse("172.26.114.71");
server = new TcpListener(localAddr, port);
server.Start();
NewConnection();
}
public void NewConnection()
{
Debugger.Break();
while (true)
{
ClientConn Client = new ClientConn();
Client.TClient = server.AcceptTcpClient();
NetworkStream stream = Client.TClient.GetStream();
data = new Byte[256];
String MSG = String.Empty;
Int32 bytes = stream.Read(data, 0, data.Length);
Client.ClientUserName = Encoding.ASCII.GetString(data, 0, bytes);
stream.Write(data, 0, bytes);
lock (ClientList)
{
ClientList.Add(Client);
}
}
}
public Boolean SendNotification(string UserName, string FFolder, string FName)
{
Debugger.Break();
NetworkStream Stream;
bool MsgSent = false;
foreach (ClientConn Client in ClientList)
{
if (Client.ClientUserName == UserName)
{
Byte[] MsgByte = Encoding.ASCII.GetBytes(FFolder + "|" + FName);
Stream = Client.TClient.GetStream();
Stream.Write(MsgByte, 0, MsgByte.Length);
MsgSent = true;
}
}
return MsgSent;
}
public void CLoseAllConnections()
{
foreach (ClientConn ConnToClose in ClientList)
{
ConnToClose.TClient.Close();
}
}
}
class ClientConn
{
private string CUser;
TcpClient Client;
public string ClientUserName
{
get { return CUser;}
set { CUser = value; }
}
public TcpClient TClient
{
get { return Client; }
set { Client = value; }
}
}
}
UPDATE:通过将运行CreateServer()的类的实例传递给最终调用SendNotification方法的线程,解决了我在下面讨论的问题。感谢您的帮助
您可以使用BlockingCollection(T)
。
class MSGServer
{
TcpListener server = null;
Int32 port = 13000;
IPAddress localAddr;
private readonly BlockingCollection<ClientConn> ClientList = new BlockingCollection<ClientConn>();
Byte[] data;
public void CreateServer()
{
localAddr = IPAddress.Parse("172.26.114.71");
server = new TcpListener(localAddr, port);
server.Start();
NewConnection();
}
public void NewConnection()
{
Debugger.Break();
while (true)
{
ClientConn Client = new ClientConn();
Client.TClient = server.AcceptTcpClient();
NetworkStream stream = Client.TClient.GetStream();
data = new Byte[256];
String MSG = String.Empty;
Int32 bytes = stream.Read(data, 0, data.Length);
Client.ClientUserName = Encoding.ASCII.GetString(data, 0, bytes);
stream.Write(data, 0, bytes);
ClientList.Add(Client);
}
}
public Boolean SendNotification(string UserName, string FFolder, string FName)
{
Debugger.Break();
NetworkStream Stream;
bool MsgSent = false;
foreach (ClientConn Client in ClientList.GetConsumingEnumerable().Where(c => c.ClientUserName == UserName))
{
Byte[] MsgByte = Encoding.ASCII.GetBytes(FFolder + "|" + FName);
Stream = Client.TClient.GetStream();
Stream.Write(MsgByte, 0, MsgByte.Length);
MsgSent = true;
}
return MsgSent;
}
public void CLoseAllConnections()
{
foreach (ClientConn ConnToClose in ClientList)
{
ConnToClose.TClient.Close();
}
}
}