2013-02-25 47 views
8

Tôi có hai ứng dụng đơn giản:C# phát hiện tcp ngắt kết nối

  • Một ứng dụng máy chủ mà chờ đợi trên một cổng tcp cụ thể đối với một khách hàng để kết nối. Sau đó, lắng nghe những gì anh ấy nói, gửi lại một số phản hồi và THAM KHẢO khách hàng đó.

  • Ứng dụng biểu mẫu kết nối với ứng dụng máy chủ, sau đó nói điều gì đó, sau đó chờ phản hồi và ngắt kết nối khỏi máy chủ, sau đó hiển thị phản hồi trong biểu mẫu.

Mặc dù ứng dụng máy chủ dường như cư xử một cách chính xác (tôi đã thử nghiệm nó với Telnet và tôi thấy ý kiến ​​phản hồi và tôi thấy các ngắt xảy ra ngay sau khi những phản hồi), việc áp dụng hình thức tuy nhiên dường như không để ý ngắt kết nối khỏi máy chủ. (TcpClient.Connected dường như vẫn đúng ngay cả sau khi máy chủ đã ngắt kết nối)

Câu hỏi của tôi là: tại sao TcpClient.Connected vẫn đúng và làm cách nào để biết khi nào máy chủ bị ngắt kết nối?

Đây là mã đầy đủ của tôi:

Mẫu ứng dụng:

using System; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

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

     private void sendButton_Click(object sender, EventArgs e) 
     { 
      TcpClient tcpClient = new TcpClient(); 
      tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 81); 
      responseLabel.Text = "waiting for response..."; 
      responseLabel.Invalidate(); 

      // write request 
      NetworkStream networkStream = tcpClient.GetStream(); 
      byte[] buffer = (new ASCIIEncoding()).GetBytes("Hello World! "); 
      networkStream.Write(buffer, 0, buffer.Length); 
      networkStream.Flush(); 

      // read response 
      Thread readThread = new Thread(new ParameterizedThreadStart(ReadResponse)); 
      readThread.Start(tcpClient); 
     } 

     void ReadResponse(object arg) 
     { 
      TcpClient tcpClient = (TcpClient)arg; 
      StringBuilder stringBuilder = new StringBuilder(); 
      NetworkStream networkStream = tcpClient.GetStream(); 
      bool timeout = false; 
      DateTime lastActivity = DateTime.Now; 
      while (tcpClient.Connected && !timeout) 
      { 
       if (networkStream.DataAvailable) 
       { 
        lastActivity = DateTime.Now; 
        while (networkStream.DataAvailable) 
        { 
         byte[] incomingBuffer = new byte[1024]; 
         networkStream.Read(incomingBuffer, 0, 1024); 
         char[] receivedChars = new char[1024]; 
         (new ASCIIEncoding()).GetDecoder().GetChars(incomingBuffer, 0, 1024, receivedChars, 0); 
         stringBuilder.Append(receivedChars); 
        } 
       } 
       else 
       { 
        if (DateTime.Now > lastActivity.AddSeconds(60)) 
         timeout = true; 
       } 
       System.Threading.Thread.Sleep(50); 
      } 
      Invoke((MethodInvoker)delegate 
      { 
       responseLabel.Text = "Response from Listener:\n" + stringBuilder.ToString(); 
       responseLabel.Invalidate(); 
      }); 

      if (timeout) 
      { 
       Console.Write("A timeout occured\n"); 
       networkStream.Close(); 
       tcpClient.Close(); 
      } 
     } 

    } 
} 

máy chủ ứng dụng:

using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System; 
using System.Threading; 

namespace Listener 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var tcpListener = new TcpListener(IPAddress.Any, 81); 
      tcpListener.Start(); 
      Thread clientThread = new Thread(new ParameterizedThreadStart(Listen)); 
      clientThread.Start(tcpListener); 
     } 

     static void Listen(object arg) 
     { 
      TcpListener tcpListener = (TcpListener)arg; 
      while (true) 
      { 
       TcpClient tcpClient = tcpListener.AcceptTcpClient(); 
       Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient)); 
       clientThread.Start(tcpClient); 
      } 
     } 

     static void HandleClient(object arg) 
     { 
      TcpClient tcpClient = (TcpClient)arg; 
      StringBuilder stringBuilder = new StringBuilder(); 
      ASCIIEncoding encoder = new ASCIIEncoding(); 
      DateTime lastActivity = DateTime.Now; 

      // read request 
      NetworkStream networkStream = tcpClient.GetStream(); 
      int timeout = 5; // gives client some time to send data after connecting 
      while (DateTime.Now < lastActivity.AddSeconds(timeout) && stringBuilder.Length==0) 
      { 
       if (!networkStream.DataAvailable) 
       { 
        System.Threading.Thread.Sleep(50); 
       } 
       else 
       { 
        while (networkStream.DataAvailable) 
        { 
         lastActivity = DateTime.Now; 
         byte[] incomingBuffer = new byte[1024]; 
         networkStream.Read(incomingBuffer, 0, 1024); 
         char[] receivedChars = new char[1024]; 
         encoder.GetDecoder().GetChars(incomingBuffer, 0, 1024, receivedChars, 0); 
         stringBuilder.Append(receivedChars); 
        } 
       } 
      } 
      string request = stringBuilder.ToString(); 

      // write response 
      string response = "The listener just received: " + request; 
      byte[] outgoingBuffer = encoder.GetBytes(response); 
      networkStream.Write(outgoingBuffer, 0, outgoingBuffer.Length); 
      networkStream.Flush(); 

      networkStream.Close(); 
      tcpClient.Close(); 
     } 
    } 

} 

Trả lời

9

TcpClient/NetworkStream không nhận được thông báo khi kết nối được đóng lại. Tùy chọn duy nhất có sẵn cho bạn là bắt ngoại lệ khi ghi vào luồng.

Một vài năm trước, chúng tôi chuyển sang sử dụng ổ cắm thay vì máy khách tcp. socket có thể sử dụng nhiều hơn so với tcpclient.

có một vài phương pháp mà bạn có thể sử dụng

Thăm dò ý kiến ​​là một trong số họ

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.poll.aspx

Bạn cũng có thể làm một kiểm tra về kết quả của bản thân Viết. nó cung cấp cho bạn số byte thực sự được viết.

Bản thân thuộc tính được kết nối chỉ phản ánh trạng thái ở thao tác cuối cùng. Tài liệu của nó nêu rõ "Giá trị của thuộc tính Connected phản ánh trạng thái của kết nối như của hoạt động gần đây nhất. Nếu bạn cần xác định trạng thái hiện tại của kết nối, thực hiện cuộc gọi Send-zero, không bị chặn. trả về thành công hoặc ném mã lỗi WAEWOULDBLOCK (10035), sau đó ổ cắm vẫn được kết nối; nếu không, ổ cắm không còn được kết nối nữa. "

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspx

+0

đã đồng ý, ổ cắm sẽ là một tùy chọn tốt hơn để sử dụng tại đây – XikiryoX

+0

NetworkStream chính nó sử dụng một Ổ cắm (mặc dù nó không phải là một đĩa công cộng). Làm thế nào tôi có thể sử dụng nó? Nói cách khác: Nếu tôi đang sử dụng Socket, làm thế nào tôi sẽ tiến hành để biết nếu khách hàng đã bị ngắt kết nối? –

+0

Hãy xem Thăm dò ý kiến ​​.. Tôi đồng ý rằng Network Stream và TcpClient sử dụng Socket nhưng chúng cung cấp một giao diện cấp cao .. Ổ cắm tuy nhiên là socket .. những gì bạn thấy là những gì bạn nhận được :) –

0
networkStream.DataAvailable 

Khách sạn này không thông báo cho bạn nếu ổ cắm đóng cửa vào phía máy chủ.

Trong trường hợp của bạn, bạn có thể thực hiện chức năng "keepalive" trong đó bạn thăm dò kết nối mỗi t phút/giây hoặc thêm nhiều lần thử/nắm bắt bất cứ khi nào bạn đọc hoặc ghi từ ổ cắm. Khi tôi sử dụng TCP, tôi chỉ bao gồm một phương thức Reconnect() đi vào mọi câu lệnh catch.

Các vấn đề liên quan