2012-05-16 39 views
6

Tôi đang viết một máy chủ với thư viện asio của boost. Máy chủ xử lý nhiều kết nối đồng thời bằng cách sử dụng một tập hợp các đối tượng Connection (một lớp bao bọc xung quanh boost :: asio :: tcp :: socket). Trong lớp Connection, socket liên tục được đọc từ việc sử dụng socket.async_read_some (...) và bất cứ khi nào trình xử lý đọc được gọi với dữ liệu mới, socket.async_read_some() ngay lập tức được gọi lại để đọc thêm dữ liệu.boost :: asio :: tcp :: socket Đóng và hủy mà không cần xử lý được gọi là

Bây giờ, máy chủ có thể quyết định ngắt kết nối máy khách vì lý do nào đó, do đó, điều tự nhiên cần thực hiện là gọi connection.close() mà lần lượt gọi socket.close(), sẽ khiến tất cả hoạt động không đồng bộ đang chờ xử lý bị hủy bỏ. Điều này làm cho trình xử lý đọc (ràng buộc với một phương thức trong lớp Connection) được gọi với boost :: asio :: error :: operation_aborted. Và vấn đề của tôi là: Tôi không muốn điều này xảy ra.

Sau socket.close(), tôi muốn hủy ổ cắm và kết nối và sau đó loại bỏ con trỏ của nó khỏi danh sách máy khách đang hoạt động của máy chủ. Tuy nhiên, trình xử lý đọc sẽ không được gọi cho đến lần lặp tiếp theo của io_service.run(), có nghĩa là tôi không thể hủy ngay lập tức socket hoặc trình xử lý đọc mà tôi đã chuyển đến socket.async_read_some() cho đến khi trình xử lý đã được gọi với lỗi. Vì vậy, tôi phải trì hoãn việc phá hủy những vật thể đó bằng cách nào đó; điều đó thật khó chịu.

Có một cách an toàn để một trong hai

  • Hủy cấp phát hoạt động async mà không cần bất kỳ handler được gọi, vì vậy tôi có thể yên tâm tiêu diệt các ổ cắm ngay sau khi socket.close(), hoặc
  • để một cách an toàn khi biết không có trình xử lý nào có thể được gọi là

Hoặc tôi đang tiếp cận cách này hoàn toàn sai?

Trả lời

4

Khi một async.operation hoàn tất - thành công hoặc có lỗi - trình xử lý hoàn thành của nó được gọi. Đây là sự bảo đảm quan trọng, và tôi không nghĩ là nên thử và "hack" hành vi này. Sự cố bạn gặp phải trong trường hợp sử dụng thường được sử dụng shared_ptr (shared_from_this thành ngữ): liên kết shared_ptr<Connection> với trình xử lý, không phát hành async_read khác khi bạn nhận được operation_aborted (hoặc một số lỗi khác), để khi tất cả trình xử lý được thực hiện đối tượng Connection bị phá hủy với socket của nó.

+0

Điều này nghe rất hay. Tôi chắc chắn không sử dụng shared_ptr đủ và thậm chí không biết về enable_shared_from_this. Tôi đã sử dụng để làm điều này: "socket.async_connect (endpoint, boost :: bind (& Connection :: done_connect, this, _1))", vì vậy bây giờ tôi chỉ cần thêm một "shared_from_this()" bổ sung vào cuộc gọi bind và cập nhật phương pháp chữ ký cho một shared_ptr bổ sung ngay cả khi shared_ptr thực tế thậm chí sẽ không được sử dụng trong xử lý? I E. shared_ptr chỉ ở đó để đảm bảo đối tượng vẫn tồn tại. Nghe có vẻ đúng? – jlh

+0

Ít nhất tôi đã thực hiện nó theo cách này và nó hoạt động rất tốt ngay bây giờ. Cảm ơn nhiều! – jlh

+0

@jlh, không hoàn toàn chính xác khi nói rằng shared_ptr "sẽ không được sử dụng trong trình xử lý". Nếu bạn liên kết một hàm thành viên với shared_ptr, nó được lưu trữ bên trong trình kết nối (hàm functor được tạo bằng bind()) và được tham chiếu trên lời gọi hàm functor. Kết quả là, con trỏ sống miễn là functor sống. –

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