2012-04-24 106 views
1

我是C#和客戶端 - 服務器編程的新手。現在,對於課堂,我試圖創建一個FTP客戶端,而不使用任何預先建立的FTP庫。我覺得我的項目大部分時間都沒有完成,但是當我做了多個需要使用數據端口的調用時(例如list,retr等),我遇到了一個問題。下面是代碼示例那是打破:第二次無法接受TcpClient C#

writer.WriteLine(portcmd); 
writer.Flush(); 

GetServerMessage(stream); 

writer.WriteLine("list "); 
writer.Flush(); 


tmpserver = new TcpListener(IPAddress.Any, 3128); 
tmpserver.Start(); 
tmpclient = tmpserver.AcceptTcpClient(); 
Console.WriteLine("gothere"); 

if (!tmpclient.Connected) 
{ 
    tmpserver.Start(); 
} 

StreamReader tmpreader = new StreamReader(tmpclient.GetStream()); 

GetServerMessage(stream); 
while (tmpreader.Peek() != -1) 
{ 
    Console.WriteLine(tmpreader.ReadLine()); 
} 

tmpclient.Close(); 
tmpserver.Stop(); 

GetServerMessage(stream); 

Getservermessage是需要一個網絡數據流,並打印出一個0.5秒的超時內一切可用的方法,流是的NetworkStream當前連接到FTP服務器,和作家是相同的包裝在StreamReader中的網絡流,便於將ASCII字符寫入服務器。如果您想知道爲什麼我使用流讀取器從數據連接中讀取數據,那是因爲服務器在傳輸數據後關閉了連接,因此我可以輕鬆獲得eof通知。我使用封閉的網絡流時,我的GetServerMessage方法出於某種原因中斷了。

此代碼正在向FTP服務器發送端口命令以通知它我將要求數據連接(前兩行)然後發送list命令,建立與服務器的數據連接,獲取所需的信息,然後終止數據連接(代碼的其餘部分)。

這段代碼在第一次運行時會沒有任何缺陷地執行,但如果再次嘗試,它會掛在'tmpclient = tmpserver.AcceptTcpClient();'線。它從來沒有達到「gothere」打印聲明。我相信這是因爲我在同一個端口上從同一臺機器接收客戶端,但我不確定。我嘗試添加一個布爾值以確保AcceptTcpClient()只運行一次,但後來出現運行時錯誤,Visual Studio告訴我可能在我完成之前釋放了資源。「我預測這會是一個問題,但是,我怎麼知道服務器在關閉一次後是否重新建立連接?

在給定的代碼結束時,我停止tmpserver並關閉tmpclient。我原來是這樣做的,因爲我知道FTP服務器在完成傳輸時會關閉連接,並認爲這是正確的做法。我發現如果我註釋掉這些代碼,代碼將會執行多次,但流顯示爲空...我不確定這些信息是否有用,但我想我會提及它。

我很抱歉,如果我一點都不清楚,但是我對這個問題的知識缺乏使我很難闡明我的問題。如果對這個問題有什麼困惑,我會很樂意嘗試清除它。

回答

3

爲了能夠接受另一個客戶端,您應該執行tmpclient = tmpserver.AcceptTcpClient();,並等待第一個客戶端(接受第二客戶端之前)完成其作品可能不是一個好主意

這裏是等待一個示例服務器代碼連接和回聲從每個客戶端發送的字符串。你可以用telnet localhost 3128

Thread t = new Thread(Server); 
t.IsBackground = true; 
t.Start(); 

測試 -

void Server() 
{ 
    TcpListener listener = new TcpListener(IPAddress.Any, 3128); 
    listener.Start(); 
    while (true) 
    { 
     var client = listener.AcceptTcpClient(); 
     new Thread(() => 
     { 
      using (client) 
      { 
       var reader = new StreamReader(client.GetStream()); 
       var writer = new StreamWriter(client.GetStream()); 
       while (true) 
       { 
        string line = reader.ReadLine(); 
        if (line == "QUIT") break; 
        writer.WriteLine("From Thread[" + Thread.CurrentThread.ManagedThreadId + "] > " + line); 
        writer.Flush(); 
       } 
      } 
     }).Start(); 
    } 
} 
+0

有了改變我的代碼工作的一點點,這似乎已經解決了我的問題,所以謝謝!我正在從FTP服務器收到另一個錯誤,現在聲明「425無法建立數據連接:地址已在使用中」 – Tom 2012-04-25 01:13:55

0

好的,就是這樣。要以簡單的方式執行服務器,您需要脫離處理客戶端套接字的代碼。當accept返回時,創建並啓動一個線程,將其傳遞給'tmpclient',然後再次循環到accept調用,以便任何新客戶端都可以連接。在新產生的服務器客戶端線程中,讀取並寫入循環中傳遞的套接字以與客戶端進行通信。

0

一旦你關閉你的tcp客戶端流,你就不能再從你從它那裏讀取的流中讀取數據。

var stream = tcpClient.GetStream(); 
... 
tcpclient.Close(); 
... 
stream.Read .. fail 

客戶將不得不請求另一個連接,

OR

您應該保留TCP客戶端套接字打開。

更復雜的服務器會保留一些關於客戶端的元數據(狀態),所以當套接字意外關閉時 - 並且客戶端很快嘗試重新連接時,服務器可以繼續順利地進行處理。