如果我在 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;
}
Run Code Online (Sandbox Code Playgroud)
您正在尝试创建AF_UNIX套接字。AF_UNIX套接字创建一个文件系统管道节点来处理连接。
在这种情况下EADDRINUSE意味着文件系统节点已经存在。实际上可能没有什么东西在监听它,但它确实存在,并且bind()因此而失败。这是套接字工作方式的一个怪癖AF_UNIX。SO_REUSEADDR是针对AF_INET或套接字的,对于套接字AF_INET6没有多大作用。AF_UNIX
strcpy(s_addr.sun_path, "server");
Run Code Online (Sandbox Code Playgroud)
您会惊讶地发现server当前目录中有一个特殊的管道文件。这就是罪魁祸首。解决方案很简单:
unlink("server");
Run Code Online (Sandbox Code Playgroud)
就在您之前bind(),现在您可以绑定它。
如果您一直在关注,您现在会想知道是否有任何事情会阻止服务器的多个实例启动、创建和bind()连接到此AF_UNIX套接字,并粗鲁地unlink连接其前身的侦听套接字,从而使您拥有服务器进程的多个实例,除了一个之外的所有实例他们现在完全没用了。这是正确的,没有什么可以阻止你这样做。
这就是为什么AF_UNIX服务器通常会采用其他方法来确保只有一个实例正在运行,例如单独的锁定文件。但这将是一个单独的问题......
| 归档时间: |
|
| 查看次数: |
132 次 |
| 最近记录: |