如何用C语言编写一个简单的Web服务器?

c,#include,#include,#include,#include,#include,,int main(int argc, char *argv[]) {, int socket_desc, client_sock, c, read_size;, struct sockaddr_in server, client;, char client_message[2000];,, // 创建套接字, socket_desc = socket(AF_INET, SOCK_STREAM, 0);, if (socket_desc == -1) {, printf("无法创建套接字");, return 1;, }, puts("套接字创建成功");,, // 准备 sockaddr_in 结构体, server.sin_family = AF_INET;, server.sin_addr.s_addr = INADDR_ANY;, server.sin_port = htons(8888);,, // 绑定, if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server))< 0) {, perror("绑定失败。错误");, return 1;, }, puts("绑定完成");,, // 监听, listen(socket_desc, 3);,, // 接受并处理连接, puts("等待连接...");, c = sizeof(struct sockaddr_in);, while ((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))) {, puts("连接已建立");,, // 接收消息, while ((read_size = recv(client_sock, client_message, 2000, 0)) > 0) {, // 发送消息回客户端, write(client_sock, client_message, strlen(client_message));, },, if (read_size == 0) {, puts("客户端断开连接");, fflush(stdout);, } else if (read_size == -1) {, perror("接收失败");, }, },, if (client_sock< 0) {, perror("接受失败");, return 1;, },, return 0;,},``

编写一个简单的Web服务器是一个有趣的项目,它可以帮助你理解网络编程的基本概念,以下是一个用C语言编写的简单Web服务器示例,这个服务器能够处理HTTP请求并返回简单的响应。

如何用C语言编写一个简单的Web服务器?

引入必要的头文件

c编写一个简单web服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

定义端口和缓冲区大小

#define PORT 8080
#define BUFFER_SIZE 1024

主函数

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    const char *hello = "HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12
Hello world!";
    // 创建套接字文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    // 绑定套接字到端口8080
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    // 读取客户端发送的数据
    read(new_socket, buffer, BUFFER_SIZE);
    printf("Request received:
%s
", buffer);
    // 发送响应给客户端
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent
");
    // 关闭套接字
    close(new_socket);
    close(server_fd);
    return 0;
}

编译和运行

将上述代码保存为simple_web_server.c,然后使用以下命令进行编译和运行:

gcc -o simple_web_server simple_web_server.c
./simple_web_server

测试服务器

打开浏览器,访问http://localhost:8080,你应该会看到"Hello world!"的消息。

相关问题与解答

问题1:如何修改服务器以处理多个并发连接?

解答:要处理多个并发连接,可以使用多线程或多进程,以下是使用多线程的示例:

如何用C语言编写一个简单的Web服务器?

#include <pthread.h>
void *handle_client(void *socket_desc) {
    int sock = *(int*)socket_desc;
    char buffer[BUFFER_SIZE] = {0};
    const char *hello = "HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12
Hello world!";
    // 读取客户端发送的数据
    read(sock, buffer, BUFFER_SIZE);
    printf("Request received:
%s
", buffer);
    // 发送响应给客户端
    send(sock, hello, strlen(hello), 0);
    printf("Hello message sent
");
    // 关闭套接字
    close(sock);
    free(socket_desc);
    return NULL;
}
int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    pthread_t thread_id;
    // 创建套接字文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    // 绑定套接字到端口8080
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    while((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))) {
        printf("Connection established
");
        int *new_sock = malloc(sizeof(int));
        *new_sock = new_socket;
        if(pthread_create(&thread_id, NULL, handle_client, (void*) new_sock) < 0) {
            perror("could not create thread");
            return 1;
        }
        printf("Handler assigned
");
    }
    if (new_socket < 0) {
        perror("accept failed");
        exit(EXIT_FAILURE);
    }
    return 0;
}

问题2:如何让服务器支持静态文件服务

解答:要让服务器支持静态文件服务,你需要解析HTTP请求中的文件路径,并根据路径读取相应的文件内容返回给客户端,以下是一个简单的示例:

#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdbool.h>
#include <errno.h>
const char *get_mime_type(const char *filename) {
    if (strstr(filename, ".html")) return "text/html";
    if (strstr(filename, ".jpg") || strstr(filename, ".jpeg")) return "image/jpeg";
    if (strstr(filename, ".png")) return "image/png";
    if (strstr(filename, ".css")) return "text/css";
    if (strstr(filename, ".js")) return "application/javascript";
    return "application/octet-stream"; // default mime type
}
void handle_client(int client_socket) {
    char buffer[BUFFER_SIZE] = {0};
    read(client_socket, buffer, BUFFER_SIZE);
    printf("Request received:
%s
", buffer);
    char method[10], path[100], protocol[10];
    sscanf(buffer, "%s %s %s", method, path, protocol);
    printf("Method: %s, Path: %s, Protocol: %s
", method, path, protocol);
    if (strcmp(method, "GET") != 0) {
        char *response = "HTTP/1.1 405 Method Not Allowed\r
\r
";
        send(client_socket, response, strlen(response), 0);
        close(client_socket);
        return;
    }
    if (path[0] != '/') { // relative path to absolute path conversion
        char abs_path[128];
        sprintf(abs_path, ".%s", path); // assuming the current directory is the root directory for simplicity
        strcpy(path, abs_path);
    }
    FILE *file = fopen(path + 1, "rb"); // skip the first character which is '/' in path
    if (!file) {
        char *response = "HTTP/1.1 404 Not Found\r
\r
";
        send(client_socket, response, strlen(response), 0);
        close(client_socket);
        return;
    }
    fseek(file, 0, SEEK_END);
    long file_size = ftell(file);
    rewind(file);
    char *content_type = get_mime_type(path + 1); // skip the first character which is '/' in path for mime type detection as well
    char *header = "HTTP/1.1 200 OK\r
";
    char content_length[50];
    sprintf(content_length, "Content-Length: %ld\r
", file_size);
    char *response = malloc(file_size + strlen(header) + strlen(content_length) + strlen("\r
\r
") + 1);
    strcpy(response, header);
    strcat(response, "Content-Type: ");
    strcat(response, content_type);
    strcat(response, "\r
");
    strcat(response, content_length);
    strcat(response, "\r
\r
");
    send(client_socket, response, strlen(response), 0); // send header first
    free(response); // free header memory after sending it out
    char data[BUFFER_SIZE]; // buffer to store file chunks to send them one by one to avoid large memory allocation at once for big files.
    while (!feof(file)) { // reading and sending file in chunks of this way can be useful when dealing with larger files to avoid high memory usage.
        int bytesRead = fread(data, 1, BUFFER_SIZE, file); // read a chunk of data from the file into 'data' buffer.
        send(client_socket, data, bytesRead, 0); // send the chunk of data to the client.
    } // end of while loop. The loop will continue until the entire file has been read and sent to the client. It ensures that even large files are handled efficiently without consuming too much memory at once. This approach is beneficial for handling large files or when dealing with limited system resources. By reading and sending the file in manageable chunks, it helps prevent high memory usage issues and ensures smoother operation even under constrained conditions.

到此,以上就是小编对于“c编写一个简单web服务器”的问题就介绍到这了,希望介绍的几点解答对大家有用,有任何问题和不懂的,欢迎各位朋友在评论区讨论,给我留言。

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/2739.html<

(0)
运维的头像运维
上一篇2024-12-02 22:21
下一篇 2024-12-02 22:25

相关推荐

  • SDNLab招聘,寻找怎样的SDN人才?

    SDNLAB作为软件定义网络领域的领先技术社区与服务平台,始终致力于推动SDN、NFV、网络自动化等前沿技术的落地与普及,随着业务规模的不断扩大和技术栈的持续深化,SDNLAB现面向社会公开招聘多个岗位,旨在吸纳行业优秀人才,共同构建开放、创新的技术生态,本次招聘涵盖技术研发、产品运营、市场推广等多个方向,无论……

    2025-11-12
    0
  • OpenDaylight SDN招聘,要求与岗位有哪些?

    随着软件定义网络(SDN)和网络功能虚拟化(NFV)技术的快速发展,OpenDaylight作为开源SDN控制器的核心平台,已成为企业网络转型和运营商网络重构的关键技术,基于此,市场对具备OpenDaylight和SDN技术能力的专业人才需求持续攀升,相关岗位涵盖开发、测试、架构、运维等多个方向,薪资待遇和发展……

    2025-11-02
    0
  • TCP/IP招聘,技能要求有哪些?

    在当前互联网技术快速发展的背景下,TCP/IP协议栈作为网络通信的核心基础,成为企业招聘网络工程师、后端开发、运维工程师等岗位时的重点考察内容,掌握TCP/IP协议的原理、网络分层模型、数据封装与解封装过程、核心协议(如TCP、UDP、IP、ICMP等)的工作机制,以及网络故障排查能力,是求职者的核心竞争力之一……

    2025-10-31
    0
  • 游戏Java岗招聘,需掌握哪些核心技能?

    在游戏行业蓬勃发展的背景下,Java开发者在游戏领域的招聘需求持续增长,尤其在服务器端开发、工具链构建和跨平台支持等方面展现出独特优势,游戏Java招聘不仅考察候选人的技术深度,更注重其对游戏业务逻辑的理解和工程化实践能力,以下从岗位需求、核心技能、行业趋势及应聘建议等方面展开分析,游戏Java开发岗位通常分为……

    2025-10-18
    0
  • 阿里DPDK招聘,需要什么技术背景?

    在当前云计算与大数据技术飞速发展的时代,高性能计算、网络加速以及智能调度已成为企业构建核心竞争力的关键,阿里作为全球领先的云计算服务提供商,始终致力于通过技术创新推动业务边界拓展,其自研的云基础设施、分布式系统以及大规模网络架构,均对底层技术提出了极致要求,DPDK(Data Plane Development……

    2025-09-28
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注