You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何为Linux下的C语言服务器-客户端程序编写GCC Makefile?

嘿,这个问题其实很常见——用一个Makefile就完全能搞定你的所有需求,而且这也是Linux C项目里最常规、最高效的做法,完全没必要分开写两个。下面我给你详细拆解实现方案,还顺带解决你提到的「仅允许运行一个服务端」的小需求。

一、单Makefile的实现方案

一个Makefile可以同时管理客户端和服务端的编译规则,既方便维护,又能一键生成两个可执行文件。

1. 编写Makefile内容

创建一个名为Makefile的文件,内容如下:

# 定义编译器和编译选项
CC = gcc
# -Wall/-Wextra 开启更多警告,-pthread 支持多线程(因为要处理多客户端)
CFLAGS = -Wall -Wextra -pthread

# 默认目标:同时生成客户端和服务端
all: client server

# 编译客户端
client: client.c util.h
	$(CC) $(CFLAGS) -o $@ $<

# 编译服务端
server: server.c util.h
	$(CC) $(CFLAGS) -o $@ $<

# 清理生成的可执行文件
clean:
	rm -f client server

2. 为什么选单Makefile?

  • 管理成本低:所有编译规则集中在一个文件里,修改、查看都更方便;
  • 操作高效:只需要执行一次make就能同时生成两个可执行文件,不用分别处理;
  • 扩展性好:后续如果新增源文件(比如util.c),直接在规则里添加即可,无需拆分文件。
二、实现「仅允许一个服务端运行」的小技巧

要保证服务端单实例运行,最可靠的方式是用文件锁(flock),它能在进程层面实现互斥,而且进程退出后锁会自动释放,不会留下脏数据。

1. 在server.c中添加单实例校验逻辑

在服务端的main函数开头加入以下代码:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PID_FILE "/var/run/my_server.pid" // 存储服务端PID的文件路径

int main() {
    // 打开或创建PID文件
    int pid_fd = open(PID_FILE, O_RDWR | O_CREAT, 0644);
    if (pid_fd == -1) {
        perror("Failed to open PID file");
        exit(EXIT_FAILURE);
    }

    // 尝试加非阻塞排他锁:如果锁失败,说明已有服务端在运行
    if (flock(pid_fd, LOCK_EX | LOCK_NB) == -1) {
        fprintf(stderr, "Error: Server is already running!\n");
        exit(EXIT_FAILURE);
    }

    // 将当前进程PID写入文件(方便后续排查)
    char pid_str[20];
    snprintf(pid_str, sizeof(pid_str), "%d\n", getpid());
    ftruncate(pid_fd, 0); // 清空文件内容
    write(pid_fd, pid_str, strlen(pid_str));

    // ---------------------
    // 这里写你的服务端核心逻辑
    // 比如监听端口、接受客户端连接、创建线程处理请求等
    // ---------------------

    return 0;
}

代码说明:

  • LOCK_EX:申请排他锁,同一时间只有一个进程能持有;
  • LOCK_NB:非阻塞模式,锁失败时直接返回错误,不会阻塞等待;
  • PID文件的作用:不仅用于加锁,还能让你通过cat /var/run/my_server.pid查看当前运行的服务端PID。
三、编译与运行说明
  1. 编译项目:在终端进入代码目录,执行:

    make
    

    执行完成后,目录下会生成clientserver两个可执行文件。

  2. 清理编译产物:如果需要重新编译,先清理旧文件:

    make clean
    
  3. 运行服务端

    ./server
    

    如果已经有一个服务端在运行,会直接输出错误并退出。

  4. 运行多客户端:打开多个终端窗口,每个窗口执行:

    ./client
    

    只要你的服务端代码已经实现了多线程(或多路复用)处理客户端连接,就能同时响应多个客户端的请求。

内容的提问来源于stack exchange,提问作者Kelve

火山引擎 最新活动