GNU/Linux >> Znalost Linux >  >> Linux

Co může způsobit „Prostředek dočasně nedostupný“ v příkazu sock send().

"Resource temporarily unavailable" je chybová zpráva odpovídající EAGAIN , což znamená, že operace by byla zablokována, ale byla požadována neblokující operace. Pro send() , to může být způsobeno některým z:

  • výslovně označit deskriptor souboru jako neblokující pomocí fcntl(); nebo
  • předání MSG_DONTWAIT příznak na send(); nebo
  • nastavení časového limitu odeslání pomocí SO_SNDTIMEO možnost zásuvky.

Uvedu příklad:

  1. klient se připojí k serveru a každou 1 sekundu odešle 1 MB dat na server.

  2. strana serveru přijme připojení a poté usne 20 sekund bez zprávy recv od klienta. Takže tcp send buffer na straně klienta bude plná.

Kód na straně klienta:

#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;
}

Kód na straně serveru:

    #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);
}

Začněte na straně serveru a poté na straně klienta.

Na straně serveru může být výstup:

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

strana klienta může vypsat:

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 

Můžete vidět, že strana serveru nezískává data od klienta, takže když strana klienta tcp buffer zaplnit, ale stále odesíláte data, takže můžete získat Resource temporarily unavailable chyba.


Je to proto, že používáte non-blocking zásuvka a výstupní vyrovnávací paměť je plná.

Z send() manuálová stránka

   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.  

ZNOVU je kód chyby spojený s „Prostředek dočasně nedostupný“

Zvažte použití select() získat lepší kontrolu nad tímto chováním


Linux
  1. Příkaz Docker se nemůže připojit k démonu Docker

  2. Jak mohu automaticky odeslat gpg šifrovanou poštu z příkazového řádku linuxu?

  3. Co by mohlo způsobit, že příkaz file v Linuxu nahlásí textový soubor jako binární data?

  1. K čemu je Linux test – příkazový test?

  2. Mohu otestovat svou vlastní síť?

  3. Co je to příkaz k nalezení priority procesu v Linuxu?

  1. Co pro vás může udělat shell dotfile

  2. Co může způsobit generování SIGHUP?

  3. Vytváření vláken se nezdaří s „Prostředky dočasně nedostupné“ s jádrem 4.3