2009-09-02 37 views
8

Tôi đang phát triển một máy chủ trong C# chỉ có thể chấp nhận một ứng dụng khách và tôi cần biết khi nào máy khách này bị ngắt kết nối để có thể chấp nhận một yêu cầu kết nối khác.Thực tiễn tốt nhất để phát hiện ngắt kết nối máy khách trong .NET?

Tôi đang sử dụng Ổ cắm đầu tiên liên tục nghe yêu cầu kết nối với Socket.BeginAccept và chấp nhận hoặc từ chối khách hàng. Khi một máy khách được chấp nhận, Socket mới được trả về bởi Socket.EndAccept được sử dụng cho giao tiếp giữa máy khách và máy chủ. Sau đó, máy chủ chờ các lệnh từ máy khách với Socket.Begin/EndReceive và gửi câu trả lời. Máy chủ sử dụng giao thức giống như Telnet, có nghĩa là mỗi lệnh và mỗi dòng phản hồi phải kết thúc bằng \r\n.

Để phát hiện xem máy khách đã bị ngắt kết nối chưa, tôi đã cài đặt bộ hẹn giờ gửi mỗi 500ms một thông báo trống ("\r\n") đến máy khách. Nếu khách hàng bị ngắt kết nối, một ngoại lệ được ném bởi Socket. Ngoại lệ này bị máy chủ chặn phải đóng phiên hiện tại và chấp nhận kết nối mới. Giải pháp này là mạnh mẽ nhưng ngụ ý lưu lượng truy cập không cần thiết qua mạng và phải được xử lý chính xác bởi ứng dụng khách phải lọc các thông điệp giả trước khi nhận được phản hồi thực tế.

Tôi đã cố gắng gửi bộ đệm trống (Socket.Send(new byte[1], 0, 0)), nhưng có vẻ như không hoạt động theo hướng máy chủ-> máy khách.

Một giải pháp khác có thể là xử lý trường hợp trong đó Socket.EndReceive trả về 0 byte. Nó hoạt động tốt cho trường hợp ngắt kết nối xảy ra trong thời gian "nhàn rỗi". Nhưng nếu khách hàng ngắt kết nối trong quá trình chuyển thư, máy chủ không phải lúc nào cũng thấy và chờ vô thời hạn.

Tôi đã xem một số chủ đề và câu hỏi về vấn đề này, nhưng tôi chưa bao giờ thấy bất kỳ giải pháp tốt nào.

Vì vậy, câu hỏi của tôi là: cách tốt nhất để phát hiện ngắt kết nối trong .Net là gì?

Trả lời

4

Tùy chọn duy nhất khác là nếu TCP là TCP để gửi một hoạt động thường xuyên, mà vẫn đang bỏ phiếu như những gì bạn đang làm bây giờ nhưng được xử lý ở lớp TCP để giao thức không không cần biết.

Không có cách nào xung quanh việc bỏ phiếu, tuy nhiên vì không gửi gì đó cho khách hàng khác và nhận được phản hồi, bạn không có cách nào để biết liệu nó có còn kết nối hay không.

Vẫn còn có thể được yêu cầu khi giao tiếp thông qua kiểm tra gói trạng thái như tiêu chuẩn NAPT để tránh việc máy chủ từ xa thả phiên do hoạt động trong.

+0

OK, tôi đã thêm mã bật KeepAlive cho ổ cắm của tôi. Nhưng tôi nghĩ điều gì sẽ xảy ra? Không có gì xảy ra khi khách hàng ngắt kết nối ... Tôi dự kiến ​​sẽ nhận được một Ngoại lệ ở đâu đó ... Tôi có nên đọc hoặc viết một cái gì đó định kỳ không? – cedrou

+1

Tôi mặc dù bạn đang sử dụng Begin/EndReceive? Nếu vậy, BeginReceive sẽ chạy gọi lại và khi bạn gọi EndReceive để có được kết quả một ngoại lệ nên được nâng lên, đó hoặc một kết thúc của dòng 0 byte đọc. –

+0

OK, bây giờ tôi có ngoại lệ ... Cảm ơn – cedrou

3

Bạn có thể sử dụng phương pháp dưới đây để tìm xem khách hàng có còn kết nối không. Điều này

public static bool IsConnected(this TcpClient client) 
{ 
    try 
    { 
     bool connected = !(client.Client.Poll(1, SelectMode.SelectRead) && client.Client.Available == 0); 

     return connected; 
    } 
    catch 
    { 
     return false; 
    } 
} 

Đây là answer dành cho ổ cắm thử nghiệm, đó là cách tôi nhận đoạn mã của mình.

+2

Phương pháp này hoạt động tốt nếu khách hàng đã đóng kết nối một cách rõ ràng, nhưng không phải nếu kết nối đã bị hỏng (ví dụ như rút phích cắm cáp). – cedrou

+0

Đó là nơi tiếp tục sống, hệ điều hành và giao thức TCP sẽ xử lý tin nhắn định kỳ cho khách hàng để xem liệu nó có còn sống hay không, và việc bỏ phiếu sẽ kiểm tra trạng thái cục bộ. Nếu vẫn tiếp tục hoạt động thì ổ cắm sẽ báo cáo rằng ổ cắm của nó không còn được kết nối nữa. –

+0

Mặc dù khi sử dụng async Begin/EndReceive bỏ phiếu không nên được yêu cầu vì bạn sẽ nhận được một cuộc gọi trở lại với lỗi khi ổ cắm không hoạt động. –

0

Bạn có quyền kiểm soát khách hàng không? Nếu vậy, bạn không thể chỉ có khách hàng gửi một gói đặc biệt đến máy chủ nói rằng nó đang ngắt kết nối, và sau đó ngắt kết nối ổ cắm?

Bạn đang cố gắng phát hiện trường hợp máy khách thực sự bị ngắt kết nối (sử dụng Socket.Shutdown() hoặc Socket.Close()) hoặc máy khách không hoạt động trong một khoảng thời gian lớn, và do đó cần bị đẩy ra?

Trong cả hai trường hợp, yêu cầu khách hàng gửi một thông báo định kỳ (giống như bạn đã thực hiện) đến máy chủ.Các máy chủ có thể theo dõi nhịp tim cuối cùng, và nếu khách hàng bỏ lỡ hơn 3 nhịp tim, bạn có thể ngắt kết nối máy khách. có, nó liên quan đến dữ liệu bổ sung, nhưng đó không phải là quá xấu trong kế hoạch lớn của sự vật. Nếu bạn điều chỉnh nó để nó gửi nhịp tim trong một khoảng thời gian đủ tốt, để bạn có được lợi thế khi biết liệu khách hàng có còn sống hay không, và đừng đi quá lâu giữa nhịp tim, bạn có thể có một hệ thống rất tốt.

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