You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Unix套接字/端口创建锁?如何用netcat等命令锁定Unix端口?

嘿,我来帮你搞定关于Unix套接字/端口锁的问题,分成两部分给你详细说明:

一、如何使用Unix套接字/端口创建锁

Unix域套接字的一个特性刚好能用来实现互斥锁:当一个进程绑定某个Unix套接字文件后,其他进程再尝试绑定同一个文件会直接失败,以此来保证同一时间只有一个进程持有“锁”。下面给你几种具体实现方式:

1. Shell脚本+Netcat实现

这是最方便的命令行级实现,适合快速给脚本加锁:

#!/bin/bash
LOCK_SOCKET="/tmp/my_app_lock.sock"

# 先检查残留的套接字文件,避免假锁
if [ -e "$LOCK_SOCKET" ]; then
    # 尝试连接套接字,判断是否真的有进程在监听
    if ! nc -U "$LOCK_SOCKET" < /dev/null >/dev/null 2>&1; then
        echo "发现残留锁文件,已清理"
        rm -f "$LOCK_SOCKET"
    else
        echo "锁已被其他进程持有,退出"
        exit 1
    fi
fi

# 尝试监听套接字,成功则拿到锁
if ! nc -U -l "$LOCK_SOCKET" >/dev/null 2>&1 &; then
    echo "获取锁失败,退出"
    exit 1
fi

LOCK_PID=$!
echo "成功获取锁,PID: $LOCK_PID"

# --------------------------
# 这里放你的业务逻辑,比如:
echo "执行任务中..."
sleep 30
# --------------------------

# 任务完成后清理锁
kill $LOCK_PID
rm -f "$LOCK_SOCKET"
echo "锁已释放"

原理:nc -U -l会绑定并监听指定的Unix套接字,后台运行后就占住了这个“锁”,其他进程再运行脚本时,nc会因为套接字已被占用而失败。

2. 使用Socat工具实现

Socat比Netcat更灵活,适合复杂场景:

#!/bin/bash
LOCK_SOCKET="/tmp/my_app_lock.sock"

# 清理残留逻辑同上
if [ -e "$LOCK_SOCKET" ]; then
    if ! socat -u UNIX-CONNECT:"$LOCK_SOCKET" /dev/null >/dev/null 2>&1; then
        rm -f "$LOCK_SOCKET"
    else
        echo "锁已被持有"
        exit 1
    fi
fi

# 监听套接字,fork参数让它后台处理连接(我们只是用它占锁)
if ! socat UNIX-LISTEN:"$LOCK_SOCKET",fork /dev/null >/dev/null 2>&1 &; then
    echo "获取锁失败"
    exit 1
fi

LOCK_PID=$!
echo "持有锁,开始执行任务..."
sleep 30

# 清理
kill $LOCK_PID
rm -f "$LOCK_SOCKET"

3. 编程层面(C语言)实现

如果需要在程序内部直接实现锁逻辑,用C语言的套接字API即可:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#define LOCK_SOCKET "/tmp/my_app_lock.sock"

int main() {
    int sockfd;
    struct sockaddr_un addr;

    // 创建Unix域套接字
    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("创建套接字失败");
        exit(EXIT_FAILURE);
    }

    // 设置套接字地址
    memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, LOCK_SOCKET, sizeof(addr.sun_path) - 1);

    // 绑定套接字,失败则判断是否锁已被占用
    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {
        if (errno == EADDRINUSE) {
            fprintf(stderr, "锁已被其他进程持有\n");
        } else {
            perror("绑定套接字失败");
        }
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 可选:监听连接(不监听也能当锁,绑定动作已经占了套接字)
    listen(sockfd, 1);

    printf("成功获取锁,开始执行任务...\n");
    sleep(30); // 模拟业务逻辑

    // 清理:关闭套接字并删除文件(必须做,否则会残留假锁)
    close(sockfd);
    unlink(LOCK_SOCKET);

    exit(EXIT_SUCCESS);
}

核心逻辑就是bind调用:当套接字已被其他进程绑定,bind会返回EADDRINUSE错误,此时就知道锁被占用了。

二、用Netcat或其他命令锁定Unix端口的具体方法

首先要明确:Unix里的“端口”这里指的是Unix域套接字文件(和TCP/UDP端口不是一个概念),用Netcat或Socat可以直接在命令行锁定它:

1. 用Netcat直接锁定

在终端运行以下命令,就能占住指定的Unix套接字当锁:

nc -U -l /tmp/my_lock.sock >/dev/null 2>&1 &

参数说明:

  • -U:指定使用Unix域套接字
  • -l:进入监听模式
  • >/dev/null 2>&1 &:后台运行并丢弃输出

释放锁的方法:

先找到Netcat的PID,杀掉后删除套接字文件:

# 查找PID并杀掉
ps aux | grep "nc -U -l /tmp/my_lock.sock" | grep -v grep | awk '{print $2}' | xargs kill
# 删除残留的套接字文件
rm -f /tmp/my_lock.sock

2. 用Socat直接锁定

Socat的命令更简洁,适合快速操作:

socat UNIX-LISTEN:/tmp/my_lock.sock,fork /dev/null &

fork参数让Socat后台处理连接,我们只需要它占住套接字即可。

释放锁的方法:

# 杀掉Socat进程
pkill -f "socat UNIX-LISTEN:/tmp/my_lock.sock"
# 删除套接字文件
rm -f /tmp/my_lock.sock

注意事项

如果持有锁的进程意外崩溃,套接字文件会残留,导致下次启动误以为锁还在。这时候可以先尝试连接套接字,判断是否真的有进程在监听,再决定是否删除残留文件(前面的脚本已经包含了这个逻辑)。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:47:06