Abra um socket em C

Este artigo irá explicar vários métodos de como abrir um soquete em C.

Use as funções listen e accept para abrir um soquete em C

listen e accept são parte dos recursos de rede do UNIX, às vezes chamados de Sockets API, que implementa a funcionalidade principal para lidar com comunicações entre processos. Observe que um soquete é uma representação abstrata do terminal para o caminho de comunicação. Existem diferentes tipos de soquetes, por exemplo, Domínio Unix e Domínio da Internet, mas todos eles seguem procedimentos semelhantes para estabelecer a comunicação entre dois processos.

Lembre-se de que a rede é apenas a comunicação entre dois programas em execução. Em primeiro lugar, a função socket é chamada para criar o endpoint e o identificador correspondente. Os soquetes são tratados com descritores de arquivo semelhantes aos arquivos regulares ou canais em sistemas UNIX. Após a chamada socket, existem dois cenários dependendo do tipo de programa que está a desenvolver. Geralmente, temos um modelo cliente-servidor na comunicação de rede, onde um programa (servidor) precisa esperar que outros (clientes) se conectem a ele.

Neste exemplo, implementamos um programa do lado do servidor que precisa ouvir o ponto de extremidade específico e aceitar conexões de cliente. Neste cenário, a função bind é chamada após socket para ligar ao endereço específico onde o programa aceitará as conexões de entrada. Depois de bind, as funções listen e accept são chamadas para formar uma chamada tomada passiva. Observe que accept bloqueia o processo até que o processo diferente não estabeleça uma conexão usando a chamada de função connect.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>

#define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define SOCKET_PATH "/tmp/my.sock"

enum {LISTEN_QUEUE = 100};

int main(int argc, char *argv[]) {
    int listenfd, connfd;
    socklen_t len;
    struct sockaddr_un servaddr, cliaddr;

    listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (listenfd == -1)
        handle_error("socket");

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sun_family = AF_UNIX;
    strncpy(servaddr.sun_path, SOCKET_PATH,sizeof(servaddr.sun_path) - 1);

    if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1)
        handle_error("bind");

    if (listen(listenfd, LISTEN_QUEUE) == -1)
        handle_error("listen");

    len = sizeof(cliaddr);
    connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &len);
    if (connfd == -1)
        handle_error("accept");

    unlink(SOCKET_PATH);
    exit(EXIT_SUCCESS);
}

Normalmente, a chamada accept é seguida pelo código que implementa o tratamento das conexões de entrada. Um programa externo que deseja estabelecer uma conexão com este servidor precisa saber o endereço e a porta. Assumindo que ambos são conhecidos pelo processo, ele invoca a função connect após a chamada de socket e esperançosamente se conecta ao processo do servidor. Uma vez que a conexão é estabelecida, ambos os processos podem escrever e ler no descritor de socket como tendo um canal bidirecional. Em cenários do mundo real, vários processos de cliente devem se conectar ao servidor simultaneamente; o código de manipulação de conexão deve ser implementado simultaneamente. Caso contrário, o servidor não poderá atender a mais de um cliente por vez.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>

#define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define SOCKET_PATH "/tmp/my.sock"

enum {MAXLINE = 4096, LISTEN_QUEUE = 100};

int main(int argc, char *argv[]) {
    int listenfd, connfd;
    socklen_t len;
    struct sockaddr_un servaddr, cliaddr;
    char buf[MAXLINE];

    listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (listenfd == -1)
        handle_error("socket");

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sun_family = AF_UNIX;
    strncpy(servaddr.sun_path, SOCKET_PATH,sizeof(servaddr.sun_path) - 1);

    if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1)
        handle_error("bind");

    if (listen(listenfd, LISTEN_QUEUE) == -1)
        handle_error("listen");

    len = sizeof(cliaddr);
    connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &len);
    if (connfd == -1)
        handle_error("accept");

    size_t ret = read(connfd, buf, MAXLINE);
    if (ret == -1)
        handle_error("read");

    printf("read %d bytes\nmessage: %s\n", connfd, buf);

    unlink(SOCKET_PATH);
    exit(EXIT_SUCCESS);
}

Artigo relacionado - C Networking

  • Encontre o nome do host do sistema em C
  • Use a função getaddrinfo em C