Aplique programação com sockets para conversar com um servidor web real e buscar HTML.
Pré-requisito: Cliente & servidor TCP simples para os fundamentos de socket/connect/send/recv.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> // close() #include <arpa/inet.h> // inet_addr(), htons() #include <netdb.h> // gethostbyname() #include <sys/socket.h> // socket(), connect(), send(), recv()
winsock2.h.#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/socket.h> #define BUF_SIZE 4096 int main(void) { const char *host = "example.com"; int port = 80; // ===== 1. Resolve hostname para IP ===== struct hostent *server = gethostbyname(host); if (server == NULL) { fprintf(stderr, "Falha na resolução do host\n"); return 1; } // ===== 2. Cria um socket ===== int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); return 1; } // ===== 3. Configura o endereço do servidor ===== struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); // porta em ordem de byte de rede memcpy(&addr.sin_addr.s_addr, server->h_addr, server->h_length); // ===== 4. Conecta ao servidor ===== if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("connect"); close(sockfd); return 1; } printf("Conectado: %s:%d\n\n", host, port); // ===== 5. Envia requisição HTTP ===== char request[BUF_SIZE]; snprintf(request, BUF_SIZE, "GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", host); send(sockfd, request, strlen(request), 0); // ===== 6. Recebe e imprime a resposta ===== char buf[BUF_SIZE]; int n; while ((n = recv(sockfd, buf, BUF_SIZE - 1, 0)) > 0) { buf[n] = '\0'; printf("%s", buf); } // ===== 7. Desconecta ===== close(sockfd); printf("\n\nConexão fechada\n"); return 0; }
| Função | Propósito | Argumentos | Retorna |
|---|---|---|---|
socket() | Cria um socket | AF_INET, SOCK_STREAM, 0 | fd do socket (int) |
gethostbyname() | Hostname → IP | "example.com" | ponteiro para hostent |
connect() | Conecta ao servidor | sockfd, addr, addrlen | 0 = ok, -1 = falha |
send() | Envia dados | sockfd, buf, len, flags | bytes enviados |
recv() | Recebe dados | sockfd, buf, len, flags | bytes recebidos (0 = fechado) |
close() | Fecha o socket | sockfd | 0 = ok |
htons() | Host-to-network short (portas) | número da porta | porta convertida |
struct sockaddr_in { short sin_family; // família do endereço (AF_INET) unsigned short sin_port; // porta (use htons() para converter) struct in_addr sin_addr; // endereço IP char sin_zero[8]; // preenchimento };
int connect_to_server(const char *host, int port). Retorne o fd do socket, ou -1 em caso de erro.send_line e recv_line que enviam e recebem uma linha por vez. send_line acrescenta \r\n; recv_line lê até \r\n../http_client example.com 80. Veja a aula de argc/argv.Teste seu entendimento desta aula!
HTTP/1.1 exige o header Host para que o servidor consiga distinguir múltiplos hosts virtuais compartilhando um IP.
Protocolos baseados em texto como HTTP e SMTP tradicionalmente separam linhas com os dois bytes CR + LF.
200 no começo de uma resposta HTTP?2xx significa sucesso, 3xx significa redirecionamento, 4xx é erro do cliente e 5xx é erro do servidor.