2009-12-17 36 views
5

Tôi có một máy chủ nhận yêu cầu kết nối từ khách hàng. Máy chủ này sử dụng phương thức Socket.BeginReceiveSocket.EndReceive không đồng bộ. Mã này khá giống với mã được tìm thấy here.C#: Làm thế nào để chấm dứt một socket trước Socket.BeginReceive gọi lại?

Trong trường hợp của tôi, sau khi gọi Socket.BeginReceive Tôi cần một thời gian chờ sao cho nếu khách hàng treo vào kết nối nhưng không truyền tải dữ liệu nào trong một khoảng thời gian nhất định, tôi cần phải chấm dứt kết nối.

  • Tôi làm cách nào để chấm dứt kết nối trong trường hợp này?
  • Cách tốt nhất để mã hóa bộ hẹn giờ là gì?

Trả lời

10

Chỉ cần gọi phương thức Close() của socket. Phương thức gọi lại sẽ chạy khá nhanh sau đó, bạn sẽ nhận được một ObjectDisposedException khi bạn gọi phương thức EndReceive(). Hãy sẵn sàng để bắt ngoại lệ đó.

Có thể bạn không muốn chặn chuỗi được gọi là BeginReceive, bạn cần có System.Threading.Timer hoặc System.Timers.Timer để phát hiện thời gian chờ. Gọi lại của nó nên gọi Close(). Cẩn thận với điều kiện chủng tộc không thể tránh khỏi điều này gây ra, gọi lại của bộ hẹn giờ sẽ chạy nếu phản hồi đã nhận được một micro giây trước khi bộ hẹn giờ hết hạn. Bạn sẽ đóng các ổ cắm, mặc dù bạn có một phản ứng tốt. Cuộc gọi tiếp theo tới BeginReceive() sẽ không thành công ngay lập tức.

+0

Bạn có nghĩa là phương thức gọi lại sẽ vẫn chạy sau khi phương thức đóng của socket được gọi? – Lopper

+1

Nếu một BeginReceive() đang chờ xử lý: có. Nó * luôn * phải được ghép nối với một cuộc gọi EndReceive(). –

+0

Cảm ơn nobugz! :) – Lopper

0

Theo bài viết MSDN trên Socket.BeginReceive nó khẳng định

Để hủy BeginReceive chờ giải quyết, gọi phương thức Close.

+0

Và để báo giá tài liệu cho phương thức Đóng: "Đối với các giao thức hướng kết nối, bạn nên gọi Tắt trước khi gọi phương thức Đóng. Điều này đảm bảo rằng tất cả dữ liệu được gửi và nhận trên ổ cắm được kết nối trước khi đã đóng cửa." –

0

Bạn có thể nhận được một số dữ liệu ban đầu một cách không đồng bộ và sau đó thực hiện đồng bộ Receive cho phần còn lại của dữ liệu và dựa vào ReceiveTimeout để ngắt kết nối máy khách. Bạn có thể sử dụng Socket.Close để ngắt kết nối máy khách một cách mạnh mẽ.

Nhưng nếu bạn muốn sử dụng async Chỉ nhận, thì bạn có thể sử dụng bộ tính giờ và đặt lại chúng trên EndReceive. Nếu nó trôi đi, bạn có thể ngắt kết nối máy khách một cách mạnh mẽ.

Nhưng tôi nghĩ cách tiếp cận đầu tiên tốt hơn.

7

Tôi biết chủ đề này là khá cũ nhưng tôi chỉ gặp phải vấn đề tương tự và tôi đã không hài lòng bởi câu trả lời được đưa ra ở đây (hoặc bất cứ nơi nào khác bởi vấn đề đó).

Giải pháp tốt hơn để hủy Socket.BeginReceive đang chờ xử lý là gọi Socket.Shutdown và không phải Socket.Close. Bằng cách này, trình xử lý asynch được nâng lên "bình thường" và một cuộc gọi đến Socket.EndReceive trả về 0 -> thay vì ném một ngoại lệ được mong đợi xấu xí. Bạn nên luôn luôn có một

if (Socket.EndReceive() > 0) { 
    //Do something 
} else { 
    //Socket has been shut down (either by you or the other end of the connection) 
    //Now it's "safe" to call Socket.Close 
    Socket.Close(); 
} 

do đó bạn thậm chí không cần phải điều chỉnh asynch-callback bạn để xử lý việc hủy bỏ bằng tay.

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