2013-06-24 53 views
0

我試圖創建一個windows服務,當文件到達FTP位置時,通過TCP向相關用戶發送消息。我已經設置了所有的文件檢測部分,但我需要一些消息傳遞方面的幫助。在1個線程中讀取列表,在另一箇中寫入

由於會有多個用戶同時訂閱此服務,因此需要能夠處理多個連接,因此我在服務啓動時創建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的方法的類的實例解決了我說的是下面的問題。感謝您的全力幫助

+1

'List'不是爲了同時修改和訪問不同的線程而設計的。您應該使用專門爲此設計的集合類型。 'BlockingCollection'應該可以滿足您的需求。 – Servy

回答

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(); 
     } 
    } 
} 
+0

感謝您的回覆,當我進入辦公室時會嘗試。非常感激。 –

+0

我認爲我仍然做錯了什麼,因爲當SendNotification方法被調用時,ClientList重置爲0.當我打電話時,我寫了 'MSGServer MSG = new MSGServer(); foreach(RequestingUserList中的字符串用戶) { MSG.SendNotification(User,FFolder,FCurrentSearch); } Conn.Close();' –

+0

'GetConsumingEnumerable'將消耗阻塞集合中的當前項目。如果你需要保存這些項目,那麼用'ToList'替換它來創建一個副本。 – Romoku

相關問題