2008-11-15 39 views
23

Có cách nào để hủy hoạt động đang chờ xử lý (không ngắt kết nối) hoặc đặt thời gian chờ cho các chức năng thư viện tăng không?Làm thế nào để thiết lập một thời gian chờ trên chặn ổ cắm trong asio tăng?

I.e. Tôi muốn thiết lập một thời gian chờ trên chặn socket trong asio tăng?

socket.read_some (tăng :: asio :: buffer (pData, maxSize), error_);

Ví dụ: Tôi muốn đọc một số từ ổ cắm, nhưng tôi muốn ném một lỗi nếu 10 giây đã trôi qua.

Trả lời

8

Dưới Linux/BSD thời gian chờ trên/O hoạt động trên ổ cắm được hỗ trợ trực tiếp bởi hệ điều hành. Có thể bật tùy chọn này qua setsocktopt(). Tôi không biết nếu boost::asio cung cấp một phương pháp để thiết lập nó hoặc cho thấy scriptor socket để cho phép bạn trực tiếp thiết lập nó - trường hợp thứ hai là không thực sự xách tay.

Đối với một vì lợi ích của sự hoàn chỉnh ở đây là mô tả từ trang người đàn ông:

SO_RCVTIMEOSO_SNDTIMEO

  Specify the receiving or sending timeouts until reporting an 
      error. The argument is a struct timeval. If an input or output 
      function blocks for this period of time, and data has been sent 
      or received, the return value of that function will be the 
      amount of data transferred; if no data has been transferred and 
      the timeout has been reached then -1 is returned with errno set 
      to EAGAIN or EWOULDBLOCK just as if the socket was specified to 
      be non-blocking. If the timeout is set to zero (the default) 
      then the operation will never timeout. Timeouts only have 
      effect for system calls that perform socket I/O (e.g., read(2), 
      recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for 
      select(2), poll(2), epoll_wait(2), etc. 
+1

Đây sẽ là một giải pháp tuyệt vời, nhưng chúng không có các tùy chọn ổ cắm như vậy. Xem các tùy chọn ổ cắm tại đây: http://www.boost.org/doc/libs/1_37_0/doc/html/boost_asio/reference.html –

+0

Tăng cường tốt nhưng không hoàn hảo :-) –

+4

Nhưng từ những gì tôi có thể nói, read_some của asio() sẽ vẫn tiếp tục nội bộ lặp mãi mãi nếu nó không đọc gì, do đó hủy bỏ hiệu quả của SO_RCVTIMEO bạn có thể đã đặt trên ổ cắm gốc. Hình như sử dụng select() với socket.native() sẽ vẫn là cách rõ ràng nhất để có thời gian chờ. –

-2

On * nix, bạn muốn sử dụng báo động() để gọi ổ cắm của bạn sẽ thất bại với EINTR

+0

Sẽ không phải tất cả các cuộc gọi ổ cắm của bạn, trong tất cả các chủ đề của bạn thất bại với EINTR? Nghe có vẻ xấu. –

9

Bạn có thể làm một async_read và cũng thiết lập một bộ đếm thời gian thời gian mong muốn của bạn. Sau đó, nếu bộ đếm thời gian kích hoạt, hãy gọi hủy trên đối tượng socket của bạn. Nếu không, nếu đọc của bạn xảy ra, bạn có thể hủy bộ hẹn giờ. Điều này đòi hỏi bạn phải sử dụng một đối tượng io_service tất nhiên.

chỉnh sửa: Tìm thấy một đoạn mã cho bạn thực hiện điều này

http://lists.boost.org/Archives/boost/2007/04/120339.php

+1

Đoạn mã này chứa một lời gọi đến 'io_service :: reset()'. Nhưng tài liệu cho nó nói 'Chức năng này không được gọi trong khi có bất kỳ cuộc gọi chưa hoàn thành nào với các hàm run(), run_one(), poll() hoặc poll_one().' – Gabriel

+0

Nếu mã này chạy trong asio async gọi lại sự kiện, đó là, bên trong một cái gì đó gọi là 'io_service :: run', tôi nghi ngờ bạn nhận được hành vi không xác định. – Gabriel

6

Tôi có cùng một câu hỏi, và sau khi một số nghiên cứu, giải pháp đơn giản nhất, sạch nhất mà tôi có thể đưa ra là để có được những cơ bản ổ cắm gốc và thực hiện lựa chọn cho đến khi có dữ liệu để đọc. Chọn sẽ mất một tham số thời gian chờ. Tất nhiên, làm việc với ổ cắm bản địa bắt đầu đi ngược lại điểm sử dụng asio ngay từ đầu, nhưng một lần nữa, điều này có vẻ là cách sạch nhất. Theo như tôi có thể nói, asio không cung cấp một cách để làm điều này để sử dụng đồng bộ một cách dễ dàng. Mã số:

 // socket here is: boost::shared_ptr<boost::asio::ip::tcp::socket> a_socket_ptr 

     // Set up a timed select call, so we can handle timeout cases. 

     fd_set fileDescriptorSet; 
     struct timeval timeStruct; 

     // set the timeout to 30 seconds 
     timeStruct.tv_sec = 30; 
     timeStruct.tv_usec = 0; 
     FD_ZERO(&fileDescriptorSet); 

     // We'll need to get the underlying native socket for this select call, in order 
     // to add a simple timeout on the read: 

     int nativeSocket = a_socket_ptr->native(); 

     FD_SET(nativeSocket,&fileDescriptorSet); 

     select(nativeSocket+1,&fileDescriptorSet,NULL,NULL,&timeStruct); 

     if(!FD_ISSET(nativeSocket,&fileDescriptorSet)){ // timeout 

       std::string sMsg("TIMEOUT on read client data. Client IP: "); 

       sMsg.append(a_socket_ptr->remote_endpoint().address().to_string()); 

       throw MyException(sMsg); 
     } 

     // now we know there's something to read, so read 
     boost::system::error_code error; 
     size_t iBytesRead = a_socket_ptr->read_some(boost::asio::buffer(myVector), error); 

     ... 

Có lẽ điều này sẽ hữu ích cho trường hợp của bạn.

2

Theo dõi những gì grepsedawk đã đề cập. Có một vài ví dụ cho thấy cách hủy hoạt động không đồng bộ dài chạy sau một khoảng thời gian, trong phần Thời gian chờ trong asio doco. Boost Asio Examples .Async TCP client helped me the most.

Chúc mừng Asyncing :)

13

Khi câu hỏi này được hỏi, tôi đoán ASIO không có bất kỳ ví dụ về cách thực hiện những gì OP cần thiết, đó là để thời gian chờ một thao tác chặn như một hoạt động ổ cắm chặn. Bây giờ có các ví dụ để cho bạn biết chính xác cách thực hiện điều này. ví dụ có vẻ dài, nhưng đó là bởi vì nó được nhận xét. Nó cho thấy làm thế nào để sử dụng ioservice trong một 'một shot' loại chế độ.

Tôi nghĩ ví dụ này là một giải pháp tuyệt vời. Các giải pháp khác ở đây phá vỡ tính di động và không tận dụng lợi thế của ioservice. nếu tính di động không quan trọng và ioservice có vẻ như nhiều chi phí - THÌ - bạn không nên sử dụng ASIO. Không có vấn đề gì, bạn sẽ có một ioservice tạo ra (gần như tất cả các chức năng ASIO phụ thuộc vào nó, thậm chí đồng bộ ổ cắm) vì vậy, tận dụng lợi thế của nó.

Timeout a blocking asio tcp operation

Timeout a blocking asio udp operation

Các tài liệu ASIO đã được cập nhật, vì vậy kiểm tra xem nó ra ví dụ mới về cách khắc phục một số ASIO 'gotchas' sử dụng để có.

+0

Trên Windows, 'io_service.run_one()' không bao giờ chặn trên async_read (ít nhất là trong Boost 1.59.0), dẫn đến việc sử dụng 100% cpu. – rustyx

+3

Các ví dụ là dài vì tài liệu là 3x dự phòng. Tôi không nghĩ rằng "WELL nhận xét". – ChristophK

1

Thậm chí nhiều năm sau câu hỏi gốc, vẫn chưa có câu trả lời thỏa mãn.

thủ sử dụng lựa chọn không phải là một lựa chọn tốt

  1. tập tin số mô tả phải nhỏ hơn 1024
  2. FD chưa spuriously báo cáo là đã sẵn sàng do checksum sai.

Gọi io_service.run_one() cũng là một ý tưởng tồi, bởi vì có thể có các tùy chọn không đồng bộ khác cần một io_service luôn là run(). Và tài liệu về việc ngăn chặn khách hàng tcp khó hiểu.

Vì vậy, đây là giải pháp của tôi. Ý tưởng chính là như sau:

{ 
    Semaphore r_sem; 
    boost::system::error_code r_ec; 
    boost::asio::async_read(s,buffer, 
          [this, &r_ec, &r_sem](const boost::system::error_code& ec_, size_t) { 
           r_ec=ec_; 
           r_sem.notify(); 
          }); 
    if(!r_sem.wait_for(std::chrono::seconds(3))) // wait for 3 seconds 
    { 
     s.cancel(); 
     r_sem.wait(); 
     throw boost::system::system_error(boost::asio::error::try_again); 
    } 
    else if(r_ec) 
     throw boost::system::system_error(r_ec); 
} 

Đây Semaphore chỉ là một mutex và điều kiện_variable.
wait_for được thực hiện bởi http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for

Full code đang tại https://github.com/scinart/cpplib/blob/master/include/asio.hpp
Các ví dụ là trong https://github.com/scinart/cpplib/blob/master/test/test_asio.cpp
Better Ví dụ tại https://github.com/scinart/cpplib/blob/master/test/test_SyncBoostIO.cpp

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