it-swarm.com.de

Was kann dazu führen, dass der Befehl sock send () vorübergehend nicht verfügbar ist

Was kann einen Resource temporarily unavailable-Fehler bei einem Socket-Befehl send() verursachen? Der Socket ist als AF_UNIX, SOCK_STREAM eingerichtet. Meistens funktioniert es, aber gelegentlich wird dieser Fehler angezeigt. Das empfangende Ende des Sockels scheint einwandfrei zu funktionieren.

Ich weiß, das ist nicht sehr detailliert, aber ich suche nur nach allgemeinen Ideen. Vielen Dank!

64
giroy

"Resource temporarily unavailable" ist die Fehlernachricht, die EAGAIN entspricht. Dies bedeutet, dass die Operation blockiert wurde, eine nicht blockierende Operation jedoch angefordert wurde. Für send() könnte das folgende Ursachen haben:

  • explizite Kennzeichnung des Dateideskriptors als nicht blockierend mit fcntl(); oder
  • MSG_DONTWAIT-Flag an send() übergeben; oder
  • einstellen eines Sendezeitlimits mit der Option SO_SNDTIMEO socket.
75
caf

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

Aus der 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.  

EAGAIN ist der Fehlercode, der an "Ressource vorübergehend nicht verfügbar" gebunden ist.

Verwenden Sie select(), um dieses Verhalten besser steuern zu können

35
Davide Berra

Lassen Sie mich ein Beispiel geben:

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

  2. server-Seite akzeptieren eine Verbindung und schlafen dann 20 Sekunden lang, ohne die Client-Nachricht erneut zu empfangen. Dadurch wird der tcp send buffer auf der Client-Seite voll.

Code auf Kundenseite:

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

Server starten, dann Client starten.

serverseite kann 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

 enter image description here

clientseitig kann ausgegeben werden:

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 

 enter image description here

Sie können sehen, da die Serverseite die Daten nicht vom Client abruft. Wenn der Clientseite tcp buffer voll wird, Sie jedoch trotzdem Daten senden, kann es sein, dass Sie Resource temporarily unavailable-Fehler erhalten.

0
Jayhello