GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Was kann eine „Ressource vorübergehend nicht verfügbar“ beim Befehl sock send() verursachen

"Resource temporarily unavailable" ist die Fehlermeldung, die EAGAIN entspricht , was bedeutet, dass der Vorgang blockiert wäre, aber ein nicht blockierender Vorgang angefordert wurde. Für send() , das könnte an einem der folgenden liegen:

  • Ausdrückliches Markieren des Dateideskriptors als nicht blockierend mit fcntl(); oder
  • Passieren der MSG_DONTWAIT Flag auf send(); oder
  • Setzen eines Sende-Timeouts mit dem SO_SNDTIMEO Socket-Option.

Lassen Sie mich ein Beispiel geben:

  1. Client stellt eine Verbindung zum Server her und sendet alle 1 Sekunde 1 MB Daten an den Server.

  2. Die Serverseite akzeptiert eine Verbindung und schläft dann 20 Sekunden lang, ohne eine Nachricht vom Client zu empfangen. Also tcp send buffer auf der Clientseite wird voll sein.

Code auf Clientseite:

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

Code auf Serverseite:

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

Serverseitig starten, dann clientseitig starten.

Serverseite kann Folgendes ausgeben:

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

Clientseite kann Folgendes ausgeben:

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 

Sie können sehen, dass die Serverseite die Daten vom Client nicht empfängt, also wenn die Clientseite tcp buffer voll werden, aber Sie senden immer noch Daten, also erhalten Sie möglicherweise Resource temporarily unavailable Fehler.


Das liegt daran, dass Sie einen non-blocking verwenden Socket und der Ausgabepuffer ist voll.

Aus dem send() Manpage

   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.  

WIEDERHER ist der Fehlercode, der mit "Ressource vorübergehend nicht verfügbar" verknüpft ist

Erwägen Sie die Verwendung von select() um dieses Verhalten besser kontrollieren zu können


Linux
  1. Was macht . ~/.bashrc Befehl Tun??

  2. Der Docker-Befehl kann keine Verbindung zum Docker-Daemon herstellen

  3. Was tun, wenn Strg + C einen Prozess nicht beenden kann?

  4. Was könnte dazu führen, dass der Dateibefehl in Linux eine Textdatei als Binärdaten meldet?

  5. Wozu dient Linux test -a command test?

Was ein Shell-Dotfile für Sie tun kann

Was ist der Linux-Überwachungsbefehl + Beispiele

Was sagt mir meine Linux-Eingabeaufforderung?

Was ist der Kill-Befehl in Linux?

Wie kann ich einen Befehl nach dem Booten ausführen?

Was ist ein Befehl, um die Priorität des Prozesses in Linux zu finden?