C语言实现简单的HTTP服务器:解析多请求行并返回响应消息
#include <netinet/in.h> #include <netinet/ip.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h>
#define ECHO_PORT 9999 #define BUF_SIZE 4096
int close_socket(int sock) { if (close(sock)) { fprintf(stderr, "Failed closing socket.\n"); return 1; } return 0; }
int main(int argc, char* argv[]) { int sock, client_sock; ssize_t readret; socklen_t cli_size; struct sockaddr_in addr, cli_addr; char buf[BUF_SIZE];
fprintf(stdout, "----- Echo Server -----\n");
/* all networked programs must create a socket */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Failed creating socket.\n");
return EXIT_FAILURE;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(ECHO_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
/* servers bind sockets to ports---notify the OS they accept connections */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)))
{
close_socket(sock);
fprintf(stderr, "Failed binding socket.\n");
return EXIT_FAILURE;
}
if (listen(sock, 5))
{
close_socket(sock);
fprintf(stderr, "Error listening on socket.\n");
return EXIT_FAILURE;
}
/* finally, loop waiting for input and then write it back */
while (1)
{
cli_size = sizeof(cli_addr);
if ((client_sock = accept(sock, (struct sockaddr *) &cli_addr,
&cli_size)) == -1)
{
close(sock);
fprintf(stderr, "Error accepting connection.\n");
return EXIT_FAILURE;
}
readret = 0;
while((readret = recv(client_sock, buf, BUF_SIZE, 0)) >= 1)
{
// 解析HTTP请求消息
char *request_line = strtok(buf, "\r\n"); // 获取请求行
if (request_line == NULL) {
// 消息格式错误
if (send(client_sock, "HTTP/1.1 400 Bad request\r\n\r\n", 29, 0) != 29) {
close_socket(client_sock);
close_socket(sock);
fprintf(stderr, "Error sending to client.\n");
return EXIT_FAILURE;
}
break;
}
char *method = strtok(request_line, " "); // 获取方法
if (method == NULL) {
// 消息格式错误
if (send(client_sock, "HTTP/1.1 400 Bad request\r\n\r\n", 29, 0) != 29) {
close_socket(client_sock);
close_socket(sock);
fprintf(stderr, "Error sending to client.\n");
return EXIT_FAILURE;
}
break;
}
if (strcmp(method, "GET") == 0 || strcmp(method, "HEAD") == 0 || strcmp(method, "POST") == 0) {
// Echo回去
if (send(client_sock, buf, readret, 0) != readret)
{
close_socket(client_sock);
close_socket(sock);
fprintf(stderr, "Error sending to client.\n");
return EXIT_FAILURE;
}
} else {
// 没有实现
if (send(client_sock, "HTTP/1.1 501 Not Implemented\r\n\r\n", 36, 0) != 36) {
close_socket(client_sock);
close_socket(sock);
fprintf(stderr, "Error sending to client.\n");
return EXIT_FAILURE;
}
}
memset(buf, 0, BUF_SIZE);
}
if (readret == -1)
{
close_socket(client_sock);
close_socket(sock);
fprintf(stderr, "Error reading from client socket.\n");
return EXIT_FAILURE;
}
if (close_socket(client_sock))
{
close_socket(sock);
fprintf(stderr, "Error closing client socket.\n");
return EXIT_FAILURE;
}
}
close_socket(sock);
return EXIT_SUCCESS;
}
原文地址: https://www.cveoy.top/t/topic/n35L 著作权归作者所有。请勿转载和采集!