Socket - File Descriptor

Los sockets son estructuras de datos que están del lado del kernel.

Para referenciarlos, el sistema operativo nos da un file descriptor (fd).

Un fd es un numero no-negativo, esto es, 0, 1 o mayores. El 0 es un file descriptor válido.

Si se quiere guardar en una variable la ausencia de un fd se debe usar un número que no se lo confunda con un fd válido. O sea, un número negativo, típicamente el -1.

int fd = -1;  // fd *no* inicializado
if (fd >= 0) {
   // fd inicializado y válido
} else {
   // fd inválido
}

Como todo recurso, este debe ser protegido en un struct (C) o clase (C++) ocultando el file descriptor de la interfaz (funciones/métodos) públicos.

/***** Archivo socket.h *****/
struct socket_t {
  int fd;
};

// Mal: el usuario del struct socket_t *sabe* y *manipula*
// file descriptors. Leakea la implementación y no es RAII.
void socket_set_fd(struct socket_t* self, int fd);
/***** Fin de socket.h *****/
/***** Archivo socket.h *****/
struct socket_t {
  int fd;
};
/***** Fin de socket.h *****/

/***** Archivo socket.c *****/
// Bien: esta función es privada: el usuario del struct socket_t
// *no* puede llamarla.
static void socket_set_fd(struct socket_t* self, int fd) {
  self->fd = fd;
}
/***** Fin de socket.c *****/
/***** Archivo socket.h *****/
class Socket {
  private:
    int fd;
  public:
    // Mal: el usuario de la clase Socket *sabe* y *manipula*
    // file descriptors. Leakea la implementación y no es RAII.
    Socket(int fd);
    /*...*/
};
/***** Fin de socket.h *****/
/***** Archivo socket.h *****/
class Socket {
  private:
    int fd;
    // Bien: este método (constructor) es privado: el usuario de la clase
    // Socket *no* puede llamarlo.
    explicit Socket(int fd);
  public:
    /*...*/
};
/***** Fin de socket.h *****/