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

时间:2013-06-24 17:08:18

标签: c# multithreading class tcp

我正在尝试创建一个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; }
        }


    }
}

更新:通过将运行CreateServer()的类的实例传递给最终调用SendNotification方法的线程,解决了我在下面讨论的问题。谢谢你的帮助

1 个答案:

答案 0 :(得分:2)

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