在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方法的线程,解决了我在下面讨论的问题。感谢您的帮助

在1个线程中读取列表,在另一个线程中写入

您可以使用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();
        }
    }
}