Một trong các dự án của tôi trên Linux sử dụng chặn ổ cắm. Mọi thứ diễn ra rất nghiêm túc nên việc không chặn sẽ khiến mọi thứ trở nên phức tạp hơn. Dù sao, tôi thấy rằng thường có một cuộc gọi recv()
đang trả lại -1
với errno
được đặt thành EAGAIN
.Trả về socket chặn EAGAIN
Trang man
chỉ thực sự đề cập đến điều này xảy ra đối với các ổ cắm không chặn, có ý nghĩa. Với không bị chặn, ổ cắm có thể có hoặc không có sẵn để bạn có thể cần phải thử lại.
Điều gì sẽ xảy ra cho ổ cắm chặn? Tôi có thể làm gì để tránh nó không?
Tại thời điểm này, mã của tôi để đối phó với nó trông giống như thế này (Tôi có nó ném một ngoại lệ về lỗi, nhưng ngoài ra nó là một wrapper rất đơn giản xung quanh recv()
):
int ret;
do {
ret = ::recv(socket, buf, len, flags | MSG_NOSIGNAL);
} while(ret == -1 && errno == EAGAIN);
if(ret == -1) {
throw socket_error(strerror(errno));
}
return ret;
Điều này có đúng không? Tình trạng EAGAIN
bị ảnh hưởng khá thường xuyên.
EDIT: một số điều tôi đã nhận thấy có thể có liên quan.
Tôi đặt thời gian chờ đọc trên ổ cắm bằng cách sử dụng
setsockopts()
nhưng được đặt thành 30 giây. cách thực hiện củaEAGAIN
thường xuyên hơn 30 giây một lần. CORRECTION gỡ lỗi của tôi bị lỗi,EAGAIN
không xảy ra thường xuyên như tôi nghĩ họ đã làm. Có lẽ nó là thời gian chờ kích hoạt.Để kết nối, tôi muốn có thể kết nối thời gian chờ, vì vậy tôi tạm thời đặt ổ cắm thành không bị chặn. mã mà trông như thế này:
int error = 0; fd_set rset; fd_set wset; int n; const SOCKET sock = m_Socket; // set the socket as nonblocking IO const int flags = fcntl (sock, F_GETFL, 0); fcntl(sock, F_SETFL, flags | O_NONBLOCK); errno = 0; // we connect, but it will return soon n = ::connect(sock, addr, size_addr); if(n < 0) { if (errno != EINPROGRESS) { return -1; } } else if (n == 0) { goto done; } FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(sock, &rset); FD_SET(sock, &wset); struct timeval tval; tval.tv_sec = timeout; tval.tv_usec = 0; // We "select()" until connect() returns its result or timeout n = select(sock + 1, &rset, &wset, 0, timeout ? &tval : 0); if(n == 0) { errno = ETIMEDOUT; return -1; } if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) { socklen_t len = sizeof(error); if (getsockopt(SOL_SOCKET, SO_ERROR, &error, &len) < 0) { return -1; } } else { return -1; } done: // We change the socket options back to blocking IO if (fcntl(sock, F_SETFL, flags) == -1) { return -1; } return 0;
Ý tưởng là tôi đặt nó là non-blocking, cố gắng một kết nối và chọn trên ổ cắm vì vậy tôi có thể thi hành một thời gian chờ. Cả hai thiết lập và khôi phục lại fcntl()
cuộc gọi trở lại thành công, do đó, các ổ cắm sẽ kết thúc trong chế độ chặn một lần nữa khi chức năng này hoàn thành.
có, nhưng nó được đặt thành 30000 mili giây, tôi nhận được * cách EAGAIN * thường xuyên hơn thế. Khá nhiều constatnly. –
* SỬA ĐỔI * gỡ lỗi của tôi đã bị thiếu sót, EAGAIN không xảy ra thường xuyên như tôi nghĩ họ đã làm. Có lẽ nó là thời gian chờ kích hoạt. –