0

我正在尝试创建一个 Windows 服务,当文件到达 FTP 位置时,通过 TCP 向相关用户发送消息。我已经设置了所有文件检测部分,但我需要在消息传递方面提供一些帮助。

由于会有多个用户同时订阅这个服务,它需要能够处理多个连接,所以我在服务启动时创建了 TCPServer 服务器,并开始监听传入的连接。当一个连接到达时,代码会将连接添加到连接列表中。

到目前为止,一切都很好。

当传入文件触发向相关客户端发送消息时,就会出现问题。尝试访问连接列表失败,因为我必须从一个单独的线程中进行操作(因为在此期间监听新连接的线程不能做任何其他事情)。

在调试模式下运行它,我看到新连接正确地增加了 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 方法的线程,解决了我在下面讨论的问题。感谢你的帮助

4

1 回答 1

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();
        }
    }
}
于 2013-06-24T17:22:01.727 回答