HTTP 通信例程
HTTP 是一种明文传输协议,在 C 语言中可以使用 socket
编程来实现简单的 HTTP 请求。以下是一个示例代码,用于向指定的 HTTP 服务器发送 GET 请求并接收响应:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
char request[BUFFER_SIZE];
// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket creation failed");
return -1;
}
// 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(80); // HTTP 默认端口
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
perror("invalid address or address not supported");
return -1;
}
// 连接到服务器
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("connection failed");
return -1;
}
// 构建 HTTP 请求
snprintf(request, sizeof(request), "GET / HTTP/1.1\r\n"
"Host: 127.0.0.1\r\n"
"Connection: close\r\n\r\n");
// 发送请求
if (send(sockfd, request, strlen(request), 0) == -1) {
perror("send failed");
return -1;
}
// 接收响应
ssize_t bytes_received;
while ((bytes_received = recv(sockfd, buffer, sizeof(buffer) - 1, 0)) > 0) {
buffer[bytes_received] = '\0';
printf("%s", buffer);
}
// 关闭套接字
close(sockfd);
return 0;
}
代码说明
- 创建套接字:使用
socket
函数创建一个 TCP 套接字。 - 设置服务器地址:设置服务器的 IP 地址和端口号。
- 连接到服务器:使用
connect
函数连接到服务器。 - 构建 HTTP 请求:构建一个简单的 HTTP GET 请求。
- 发送请求:使用
send
函数发送请求。 - 接收响应:使用
recv
函数接收服务器的响应。 - 关闭套接字:使用
close
函数关闭套接字。
HTTPS 通信例程
HTTPS 是基于 HTTP 的安全传输协议,需要使用 SSL/TLS 进行加密。在 C 语言中可以使用 OpenSSL 库来实现 HTTPS 通信。以下是一个示例代码,用于向指定的 HTTPS 服务器发送 GET 请求并接收响应:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define BUFFER_SIZE 1024
void init_openssl() {
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
void cleanup_openssl() {
EVP_cleanup();
ERR_free_strings();
}
SSL_CTX *create_context() {
const SSL_METHOD *method;
SSL_CTX *ctx;
method = SSLv23_client_method();
ctx = SSL_CTX_new(method);
if (!ctx) {
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
return NULL;
}
return ctx;
}
void configure_context(SSL_CTX *ctx) {
SSL_CTX_set_ecdh_auto(ctx, 1);
// 验证服务器证书
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
if (SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs") != 1) {
ERR_print_errors_fp(stderr);
}
}
int main() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
char request[BUFFER_SIZE];
SSL_CTX *ctx;
SSL *ssl;
// 初始化 OpenSSL
init_openssl();
// 创建 SSL 上下文
ctx = create_context();
if (!ctx) {
cleanup_openssl();
return -1;
}
// 配置 SSL 上下文
configure_context(ctx);
// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket creation failed");
SSL_CTX_free(ctx);
cleanup_openssl();
return -1;
}
// 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(443); // HTTPS 默认端口
if (inet_pton(AF_INET, "www.example.com", &server_addr.sin_addr) <= 0) {
perror("invalid address or address not supported");
close(sockfd);
SSL_CTX_free(ctx);
cleanup_openssl();
return -1;
}
// 连接到服务器
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("connection failed");
close(sockfd);
SSL_CTX_free(ctx);
cleanup_openssl();
return -1;
}
// 创建 SSL 连接
ssl = SSL_new(ctx);
if (!ssl) {
perror("unable to create SSL connection");
close(sockfd);
SSL_CTX_free(ctx);
cleanup_openssl();
return -1;
}
// 将 SSL 连接与套接字关联
if (SSL_set_fd(ssl, sockfd) != 1) {
perror("unable to set SSL fd");
SSL_free(ssl);
close(sockfd);
SSL_CTX_free(ctx);
cleanup_openssl();
return -1;
}
// 执行 SSL 握手
if (SSL_connect(ssl) != 1) {
ERR_print_errors_fp(stderr);
SSL_free(ssl);
close(sockfd);
SSL_CTX_free(ctx);
cleanup_openssl();
return -1;
}
// 构建 HTTP 请求
snprintf(request, sizeof(request), "GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Connection: close\r\n\r\n");
// 发送请求
if (SSL_write(ssl, request, strlen(request)) <= 0) {
ERR_print_errors_fp(stderr);
SSL_free(ssl);
close(sockfd);
SSL_CTX_free(ctx);
cleanup_openssl();
return -1;
}
// 接收响应
ssize_t bytes_received;
while ((bytes_received = SSL_read(ssl, buffer, sizeof(buffer) - 1)) > 0) {
buffer[bytes_received] = '\0';
printf("%s", buffer);
}
// 关闭 SSL 连接
SSL_shutdown(ssl);
SSL_free(ssl);
// 关闭套接字
close(sockfd);
// 清理 OpenSSL
SSL_CTX_free(ctx);
cleanup_openssl();
return 0;
}
代码说明
- 初始化 OpenSSL:调用
init_openssl
函数初始化 OpenSSL 库。 - 创建 SSL 上下文:调用
create_context
函数创建 SSL 上下文。 - 配置 SSL 上下文:调用
configure_context
函数配置 SSL 上下文,包括验证服务器证书。 - 创建套接字:使用
socket
函数创建一个 TCP 套接字。 - 设置服务器地址:设置服务器的 IP 地址和端口号。
- 连接到服务器:使用
connect
函数连接到服务器。 - 创建 SSL 连接:使用
SSL_new
函数创建 SSL 连接,并使用SSL_set_fd
函数将 SSL 连接与套接字关联。 - 执行 SSL 握手:使用
SSL_connect
函数执行 SSL 握手。 - 构建 HTTP 请求:构建一个简单的 HTTP GET 请求。
- 发送请求:使用
SSL_write
函数发送请求。 - 接收响应:使用
SSL_read
函数接收服务器的响应。 - 关闭 SSL 连接:使用
SSL_shutdown
和SSL_free
函数关闭 SSL 连接。 - 关闭套接字:使用
close
函数关闭套接字。 - 清理 OpenSSL:调用
cleanup_openssl
函数清理 OpenSSL 库。
编译和运行
HTTP 例程
gcc http_example.c -o http_example
./http_example
HTTPS 例程
gcc https_example.c -o https_example -lssl -lcrypto
./https_example
以上代码仅是简单示例,实际应用中可能需要更多的错误处理和安全性检查。