GNU/Linux >> Tutoriales Linux >  >> Linux

¿Qué puede causar un "Recurso temporalmente no disponible" en el comando sock send ()?

"Resource temporarily unavailable" es el mensaje de error correspondiente a EAGAIN , lo que significa que la operación se habría bloqueado pero se solicitó una operación sin bloqueo. Para send() , eso podría deberse a cualquiera de:

  • marcar explícitamente el descriptor de archivo como no bloqueante con fcntl(); o
  • pasando el MSG_DONTWAIT marcar a send(); o
  • establecer un tiempo de espera de envío con el SO_SNDTIMEO opción de enchufe.

Permítanme dar un ejemplo:

  1. el cliente se conecta al servidor y envía 1 MB de datos al servidor cada segundo.

  2. el lado del servidor acepta una conexión y luego duerme 20 segundos, sin recibir un mensaje del cliente. Así que el tcp send buffer en el lado del cliente estará lleno.

Código en el lado del cliente:

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

Código en el lado del servidor:

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

Empezar del lado del servidor, luego del lado del cliente.

el lado del servidor puede generar:

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

el lado del cliente puede generar:

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 

Puede ver, como el lado del servidor no recibe los datos del cliente, entonces cuando el lado del cliente tcp buffer se llena, pero aún envía datos, por lo que puede obtener Resource temporarily unavailable error.


Eso es porque estás usando un non-blocking socket y el búfer de salida está lleno.

Del send() página 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.  

EAGAIN es el código de error vinculado a "Recurso temporalmente no disponible"

Considere usar select() para tener un mejor control de estos comportamientos


Linux
  1. ¿Cómo puedo excluir un directorio del comando ls?

  2. El comando Docker no se puede conectar al demonio Docker

  3. ¿Qué hacer cuando Ctrl + C no puede matar un proceso?

  4. ¿Cómo puedo ejecutar un comando después del arranque?

  5. ¿Qué comando se puede usar para forzar la liberación de todo en la partición de intercambio a la memoria?

¿Qué es el comando Watch de Linux + ejemplos?

¿Qué me dice el símbolo del sistema de Linux?

¿Qué es el comando matar en Linux?

¿Cuál es el propósito de cd ` (comilla grave)?

¿Puedo probar mi propia red?

¿Qué es un comando para encontrar la prioridad del proceso en Linux?