如果我在Linux上启动本地服务器,我会收到"地址已在使用"错误.

我用了setsockopt(SO_REUSEADDR),但没用.我怎么才能解决这个问题呢? 代码:

#include <iostream>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
using namespace std;

int main() {
    sockaddr_un s_addr;
    s_addr.sun_family = AF_UNIX;
    strcpy(s_addr.sun_path, "server");

    int s_descriptor = socket(AF_UNIX, SOCK_STREAM, 0);

    const int par = 1;
    if (setsockopt(s_descriptor, SOL_SOCKET, SO_REUSEADDR, &par, sizeof(int)) < 0){
        cout << "Error setsockopt()";
        return -1;
    }

    if (bind(s_descriptor, (sockaddr *)&s_addr, sizeof(s_addr)) < 0) {
        cout << "Error with bind()\n";
        cout << strerror(errno);
        return -2;
    }

    close(s_descriptor);
    return 0;
}

推荐答案

您正在try 创建AF_UNIX套接字.AF_UNIX个套接字创建一个文件系统管道 node 来处理连接.

在这种情况下,EADDRINUSE意味着文件系统 node 已经存在.可能实际上没有人在监听它,但它确实存在,因此bind()失败了.这是AF_UNIX套接字工作方式的一个怪癖.SO_REUSEADDR用于AF_INETAF_INET6套接字,对AF_UNIX套接字没有太大作用.

strcpy(s_addr.sun_path, "server");

您会惊讶地发现,在当前目录中有一个server特殊的管道文件.这才是罪魁祸首.解决方案非常简单:

unlink("server");

就在你bind()岁之前,现在你可以绑定它了.

如果您一直在关注,您现在会想知道是否有什么东西阻止了您的服务器的多个实例启动、创建和bind()到这个AF_UNIX套接字,并粗暴地unlink个它的前身的侦听套接字,留下了服务器进程的多个实例,除了一个之外,所有的实例现在都是完全无用的.这是正确的,没有什么能阻止你这样做.

这就是为什么AF_UNIX台服务器通常会使用其他方法来确保它们中只有一个实例在运行,比如单独的锁文件.但这将是一个单独的问题...

Linux相关问答推荐

AWK打印到文件正在追加,而不是覆盖

C++调试器如何知道如何在源代码和可执行文件之间映射行?

/proc/mounts 没有像 /proc/self/mountinfo 这样的源信息

在 bash 脚本中保持两个进程处于活动状态(并在死亡时重生它们)

如何使用 Linux 命令行跨子目录查找相似的文件名?

如何使用 sed 和 awk 命令提取模式?

使用ansible配置Linux VM使用vmware_vm_shell模块时变成su?

在 Ubuntu 中,如何设置 Tomcat 9 以使用 Java 17?

Google Cloud Ops Agent Mongo 集成错误 - AuthenticationFailed:SCRAM 身份验证失败,storedKey 不匹配

构建 python 映像时 Docker compose 问题,访问被拒绝或存储库不存在

Linux 如何将主机文件作为用户的输入并将其调用到脚本中

在 SLURM 作业(job)脚本中设置和传递字符串变量

是否可以在 XTerm 或 Konsole 中使 stdout 和 stderr 输出具有不同的 colored颜色 ?

使用 shell 脚本获取 MAC 地址

KDE 桌面效果中的 OpenGL 和 XRender 有什么区别?

如何在 Ubuntu 12.04 中更改 Jenkins 安装的端口号

size_t 和 off_t 的用法有什么区别?

`是什么意思! -d` 在这个 Bash 命令中?

在 Ubuntu 中学习 OpenGL

如何在 linux 中使用 CMake 和 Kdevelop 编译 GLUT + OpenGL 项目?