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 <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.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 <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.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);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook