2010-10-12 54 views
0

嘿,所有。我正在編寫一個簡單的客戶端/服務器應用程序(僅僅爲了體驗,網絡對我來說是相當新的),客戶端發送服務器數據並將其輸出到文本框。它一切正常,除了一個小細節......有時候會建立一個連接,但數據不會被髮送或讀取(無法解決問題),因此文本框中沒有輸出任何內容。每次建立連接時,計數器都會增加,當收到數據塊時也是如此。當你比較兩者時,連接的數量是正確的,但數據計數器通常較低,有時會減少一半。無論如何,如果任何人都可以給我一些建議或指引我正確的方向,那將不勝感激!C#TcpClient沒有發送或讀取100%的數據?

下面的代碼,如果你需要它:

(SERVER_CODE)

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 

namespace Server 
{ 
    public partial class Form1 : Form 
    { 
     public int Connections = 0; 
     public int blocks = 0; 
     public int threads = 0; 
     public Thread MasterThread; 
     public TcpListener Master; 
     public volatile bool Run; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 

     public void StartMaster() 
     { 
      Master = new TcpListener(IPAddress.Any, 1986); 
      Master.Start(); 
      MasterThread = new Thread(new ThreadStart(RunMaster)); 
      MasterThread.Start(); 
     } 

     public void RunMaster() 
     { 
      threads++; 
      label6.Text = String.Format("{0}", threads); 

      while (Run) 
      { 
       TcpClient client = Master.AcceptTcpClient(); 
       Connections++; 
       label4.Text = String.Format("{0}", Connections); 
       Thread ClientThread = new Thread(new ParameterizedThreadStart(RunClient)); 
       ClientThread.Start(client); 
      } 

      Master.Stop(); 

      threads--; 
      label6.Text = String.Format("{0}", threads); 
     } 

     public void RunClient(object tcpClient) 
     { 
      TcpClient client = (TcpClient)tcpClient; 
      byte[] buffer = new byte[4096]; 
      int byteCount = 0; 
      NetworkStream stream = client.GetStream(); 
      threads++; 
      label6.Text = String.Format("{0}", threads); 

      while (Run) 
      { 
       try 
       { 
        byteCount = stream.Read(buffer, 0, 4096); 
       } 
       catch 
       { 
        //Connections--; 
        break; 
       } 

       if (byteCount == 0) 
       { 
        //Connections--; 
        break; 
       } 

       blocks++; 
       label5.Text = String.Format("{0}", blocks); 

       textBox1.AppendText(Encoding.ASCII.GetString(buffer, 0, byteCount) + "\r\n"); 
      } 

      client.Close(); 

      threads--; 
      label6.Text = String.Format("{0}", threads); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      Run = true; 
      StartMaster(); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      Run = false; 
     } 
    } 
} 

(CLIENT_CODE)

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 

namespace Client 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1986); 
      TcpClient client = new TcpClient(); 
      try 
      { 
       client.Connect(endPoint); 
      } 
      catch 
      { 
       MessageBox.Show("Connect Error"); 
      } 

      NetworkStream stream = client.GetStream(); 
      byte[] data = Encoding.ASCII.GetBytes(textBox1.Text); 
      stream.Write(data, 0, data.Length); 
      stream.Flush(); 
      client.Close(); 
     } 
    } 
} 

感謝信,
特里斯坦!

回答

2

好了,開始與你在這削弱自己的診斷:

catch 
{ 
    //Connections--; 
    break; 
} 

你爲什麼吞嚥異常沒有任何登錄等?也許正在拋出一個異常,你無法知道。理想情況下,你應該抓住具體例外,當你做異常至少日誌是怎麼回事。

另一方面,Wireshark應該可以幫助您確定數據是否正在發送。

+0

嗨,感謝您的提示!我添加了一些日誌記錄,僅用於測試,當拋出異常時彈出一個消息框。但是,似乎什麼也沒有拋出。所以我認爲我的問題可能存在於其他地方...... – Tristan 2010-10-12 09:44:02

1

我還沒有徹底瞭解您的代碼,但經過快速瀏覽之後,您可以在沒有正確鎖定的情況下訪問來自多個線程的變量。像x++;這樣的語句必須讀取x的值,將其增加並寫回。如果您需要從多個線程訪問的變量,總是同步的,除非你知道自己在做什麼

x = 0 

Thread 1   Thread 2 
------------------------ 
Read (0) 
        Read (0) 
Increment (1) 
        Increment (1) 
Write (1) 
        Write (1) 

=> x = 1 instead of 2 

:現在,如果你有兩個線程這樣做,你可能會遇到這種情況。例如,創建和使用一個同步對象是這樣的:

int threads = 0; 
object threadSync = new object(); 

... 

lock (threadSync) { 
    threads++; 
} 

然後只有一個線程可以每次訪問變量和值被正確遞增。

編輯:另一個問題是,您從不同於創建它們的線程訪問可見控件。早期的.NET版本允許這樣做,但新版本不允許。如果需要更新狀態消息,則需要查看控件的InvokeRequired屬性,如果設置爲true,則使用Control.Invoke(...)調用設置該屬性的方法。

+0

提及對UI的序列化訪問......調用窗體的「BeginInvoke」方法將執行此操作。 – 2010-10-12 08:41:48

+0

嗨,感謝您的信息,我已經做了一些編輯並添加了同步,並且爲控件的invoke方法創建了委託函數來修改其屬性。雖然,我的問題依然存在,所以我不得不深入研究它... – Tristan 2010-10-12 09:48:55