GNU/Linux >> Linux Esercitazione >  >> Linux

Cosa può causare un comando "Risorsa temporaneamente non disponibile" sul comando sock send()

"Resource temporarily unavailable" è il messaggio di errore corrispondente a EAGAIN , il che significa che l'operazione sarebbe stata bloccata ma è stata richiesta un'operazione non bloccante. Per send() , che potrebbe essere dovuto a uno qualsiasi di:

  • contrassegnare esplicitamente il descrittore di file come non bloccante con fcntl(); o
  • superando il MSG_DONTWAIT flag a send(); o
  • impostando un timeout di invio con il SO_SNDTIMEO opzione socket.

Facciamo un esempio:

  1. il client si connette al server e invia 1 MB di dati al server ogni secondo.

  2. il lato server accetta una connessione, quindi dorme 20 secondi, senza ricevere messaggi dal client. Quindi il tcp send buffer nel lato client sarà pieno.

Codice lato client:

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

Codice lato server:

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

Avvia lato server, quindi avvia lato client.

il lato server può restituire:

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

il lato client può restituire:

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 

Puoi vedere, poiché il lato server non riceve i dati dal client, quindi quando il lato client tcp buffer si riempie, ma invii comunque dati, quindi potresti ottenere Resource temporarily unavailable errore.


Questo perché stai usando un non-blocking socket e il buffer di output è pieno.

Dal send() pagina man

   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.  

ANCORA è il codice di errore legato a "Risorsa temporaneamente non disponibile"

Prendi in considerazione l'utilizzo di select() per ottenere un migliore controllo di questi comportamenti


Linux
  1. Cosa fa . ~/.bashrc Comando Fare??

  2. Cosa può causare la generazione di SIGHUP?

  3. Come posso escludere una directory dal comando ls

  4. Cosa fare quando Ctrl + C non può terminare un processo?

  5. Cosa potrebbe far sì che il comando file in Linux riporti un file di testo come dati binari?

Cosa può fare per te un file dot di shell

Cos'è il comando Linux Watch + Esempi

Cosa mi dice il mio prompt dei comandi di Linux?

Qual è il comando kill in Linux?

Posso testare la mia rete?

Quale comando può essere utilizzato per forzare il rilascio di tutto nella partizione di swap in memoria?