Điều gì có thể gây ra "Tài nguyên tạm thời không khả dụng" trên lệnh sock send ()


82

Điều gì có thể gây ra Resource temporarily unavailablelỗi trên send()lệnh socket ? Ổ cắm được thiết lập như AF_UNIX, SOCK_STREAM. Nó hoạt động hầu hết thời gian, nhưng đôi khi gặp lỗi này. Đầu nhận của ổ cắm dường như đang hoạt động bình thường.

Tôi biết điều này không quá chi tiết, nhưng tôi chỉ đang tìm kiếm những ý tưởng chung. Cảm ơn!


Cái này có liên quan không? stackoverflow.com/questions/5737493/…
paddy

3
Bạn có đang đặt ổ cắm của mình thành O_NONBLOCK không?
Deepankar Bajpeyi

Tôi không nghĩ rằng nó có liên quan đến bài đăng đó. Ổ cắm của tôi là SOCK_STREAM mà tôi tin rằng đang chặn, đó là những gì tôi muốn.
giroy

2
Việc luồng đang chặn hay không chặn không phụ thuộc vào việc luồng đó là SOCK_STREAM hay SOCK_DGRAM. Câu trả lời có liên quan.
Barmar

Câu trả lời:


95

"Resource temporarily unavailable"là thông báo lỗi tương ứng với EAGAIN, có nghĩa là hoạt động sẽ bị chặn nhưng hoạt động không chặn đã được yêu cầu. Đối với send(), điều đó có thể là do bất kỳ:

  • đánh dấu rõ ràng trình mô tả tệp là không chặn với fcntl(); hoặc là
  • truyền MSG_DONTWAITcờ cho send(); hoặc là
  • đặt thời gian chờ gửi bằng SO_SNDTIMEOtùy chọn ổ cắm.

Nguyên nhân của sự cố của tôi là đặt thời gian chờ gửi. Cảm ơn bạn vì sự giúp đỡ của bạn!
giroy 17/113

@caf, Trong trường hợp của tôi, cấu hình kích thước MTU khác nhau ở hai bên đã khiến liên kết sctp Txqueue bị tràn khi tốc độ trao đổi gói cao đang xảy ra. Làm cho MTU giống nhau trên cả hai hệ thống đã làm cho vấn đề biến mất. Nhưng bất cứ ai có thể vui lòng giải thích lý do đằng sau vấn đề là gì?
Codename_DJ

45

Đó là bởi vì bạn đang sử dụng một non-blockingổ cắm và bộ đệm đầu ra đã đầy.

Từ send()trang người đàn ông

   When the message does not fit into  the  send  buffer  of  the  socket,
   send() normally blocks, unless the socket has been placed in non-block-
   ing I/O mode.  In non-blocking mode it  would  return  EAGAIN  in  this
   case.  

EAGAIN là mã lỗi liên quan đến "Tài nguyên tạm thời không khả dụng"

Cân nhắc sử dụng select()để kiểm soát tốt hơn các hành vi này


@giroy: nhưng không thực sự đúng ... thực sự là một chặn ổ cắm, vớiSO_SNDTIMEO
EML

Tuyệt nhưng làm thế nào chúng ta có thể sử dụng kết nối khác để quản lý việc đọc đồng thời trong DB?
MUY Bỉ

8

Hãy để tôi đưa ra một ví dụ:

  1. máy khách kết nối với máy chủ và gửi 1MB dữ liệu đến máy chủ sau mỗi 1 giây.

  2. phía máy chủ chấp nhận một kết nối và sau đó ở chế độ ngủ 20 giây, không có tin nhắn gửi lại từ tcp send buffermáy khách. Vì vậy, phía máy khách sẽ đầy.

Mã ở phía máy khách:

#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define exit_if(r, ...)                                                                          \
    if (r) {                                                                                     \
        printf(__VA_ARGS__);                                                                     \
        printf("%s:%d error no: %d error msg %s\n", __FILE__, __LINE__, errno, strerror(errno)); \
        exit(1);                                                                                 \
    }

void setNonBlock(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    exit_if(flags < 0, "fcntl failed");
    int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    exit_if(r < 0, "fcntl failed");
}

void test_full_sock_buf_1(){
    short port = 8000;
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;


    int fd = socket(AF_INET, SOCK_STREAM, 0);
    exit_if(fd<0, "create socket error");

    int ret = connect(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr));
    exit_if(ret<0, "connect to server error");
    setNonBlock(fd);

    printf("connect to server success");

    const int LEN = 1024 * 1000;
    char msg[LEN];  // 1MB data
    memset(msg, 'a', LEN);

    for (int i = 0; i < 1000; ++i) {
        int len = send(fd, msg, LEN, 0);
        printf("send: %d, erron: %d, %s \n", len, errno, strerror(errno));
        sleep(1);
    }

}

int main(){
    test_full_sock_buf_1();

    return 0;
}

Mã ở phía máy chủ:

    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <string.h>
    #define exit_if(r, ...)                                                                          \
        if (r) {                                                                                     \
            printf(__VA_ARGS__);                                                                     \
            printf("%s:%d error no: %d error msg %s\n", __FILE__, __LINE__, errno, strerror(errno)); \
            exit(1);                                                                                 \
        }
void test_full_sock_buf_1(){

    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    exit_if(listenfd<0, "create socket error");

    short port = 8000;
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    int r = ::bind(listenfd, (struct sockaddr *) &addr, sizeof(struct sockaddr));
    exit_if(r<0, "bind socket error");

    r = listen(listenfd, 100);
    exit_if(r<0, "listen socket error");

    struct sockaddr_in raddr;
    socklen_t rsz = sizeof(raddr);
    int cfd = accept(listenfd, (struct sockaddr *) &raddr, &rsz);
    exit_if(cfd<0, "accept socket error");

    sockaddr_in peer;
    socklen_t alen = sizeof(peer);
    getpeername(cfd, (sockaddr *) &peer, &alen);

    printf("accept a connection from %s:%d\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));

    printf("but now I will sleep 15 second, then exit");
    sleep(15);
}

Bắt đầu phía máy chủ, sau đó bắt đầu phía máy khách.

phía máy chủ có thể xuất:

accept a connection from 127.0.0.1:35764
but now I will sleep 15 second, then exit
Process finished with exit code 0

nhập mô tả hình ảnh ở đây

phía khách hàng có thể xuất:

connect to server successsend: 1024000, erron: 0, Success 
send: 1024000, erron: 0, Success 
send: 1024000, erron: 0, Success 
send: 552190, erron: 0, Success 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 11, Resource temporarily unavailable 
send: -1, erron: 104, Connection reset by peer 
send: -1, erron: 32, Broken pipe 
send: -1, erron: 32, Broken pipe 
send: -1, erron: 32, Broken pipe 
send: -1, erron: 32, Broken pipe 
send: -1, erron: 32, Broken pipe 

nhập mô tả hình ảnh ở đây

Bạn có thể thấy, vì phía máy chủ không lấy lại dữ liệu từ máy khách, vì vậy khi phía máy khách tcp bufferđầy nhưng bạn vẫn gửi dữ liệu, vì vậy bạn có thể gặp Resource temporarily unavailablelỗi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.