首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SO_REUSEADDR和SO_REUSEPORT的行为发生了变化?

SO_REUSEADDR和SO_REUSEPORT的行为发生了变化?
EN

Stack Overflow用户
提问于 2015-09-18 21:10:34
回答 2查看 4.4K关注 0票数 7

在旧版本的Mac中,通配符绑定的工作方式如下所述:

他们有什么区别?它们在所有主要操作系统中都是相同的吗?

多播地址 SO_REUSEADDR对于多播地址的含义会发生变化,因为它允许将多个套接字绑定到源多播地址和端口的完全相同的组合中。换句话说,对于多播地址,SO_REUSEADDR的行为与单播地址的SO_REUSEPORT完全一样。实际上,对于多播地址,代码对SO_REUSEADDR和SO_REUSEPORT的处理是相同的,这意味着SO_REUSEADDR对所有多播地址都意味着SO_REUSEPORT,而相反。

MacOS X 在其核心,MacOS X只是一个BSD风格的UNIX,基于一个相当晚的分叉的BSD代码,它甚至与FreeBSD 5同步为MacOS10.3发行版。这就是为什么MacOS X提供了与BSD相同的选项,它们的行为方式也与BSD相同。

但在10.10.5中,我在测试我的网络库时发现了一个变化。

两个未绑定(通配符) UDP套接字不能再共享同一个端口(errno=EADDRINUSE),即使设置了SO_REUSEADDR。SO_REUSEPORT必须同时设置两个,这对我来说是个谜。

这个简单的测试代码是可以复制的:

代码语言:javascript
复制
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

int main() {
    for(int p = 0; p < 4; ++p) {
        printf("Flags set: ");
        if(p&1) printf("SO_REUSEADDR ");
        if(p&2) printf("SO_REUSEPORT");
        printf("\n");

        int handles[2];
        bool success = true;
        for(int i = 0; i < sizeof(handles)/sizeof(int); ++i) {
            handles[i] = socket(AF_INET, SOCK_DGRAM, 0);

            int flag = 1;
            if((p&1) && setsockopt(handles[i], SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) {
                printf("Setsockopt %d, SO_REUSEADDR failed with errno\n", i, errno);
                success = false;
                break;
            }
            if((p&2) && setsockopt(handles[i], SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)) == -1) {
                printf("Setsockopt %d, SO_REUSEPORT failed with errno\n", i, errno);
                success = false;
                break;
            }

            struct sockaddr_in addr;
            memset(&addr, 0, sizeof(addr));
            addr.sin_family = AF_INET;
            addr.sin_port = 2000; // does not matter as long as it is currently free
            addr.sin_addr.s_addr = 0; // wildcard address

            if(bind(handles[i], (struct sockaddr*)&addr, sizeof(addr)) == -1) {
                printf("Bind %d failed with errno %d\n", i, errno);
                success = false;
                break;
            }
        }
        if(success)
            printf("Alright\n");

        for(int i = 0; i < sizeof(handles)/sizeof(int); ++i)
            close(handles[i]);
        printf("\n");
    }

    return 0;
}

其中产出:

代码语言:javascript
复制
Flags set: 
Bind 1 failed with errno 48

Flags set: SO_REUSEADDR 
Bind 1 failed with errno 48

Flags set: SO_REUSEPORT
Alright

Flags set: SO_REUSEADDR SO_REUSEPORT
Alright
EN

回答 2

Stack Overflow用户

发布于 2016-01-15 14:15:13

在旧版本的Mac中,通配符绑定的工作方式如下所述: 他们有什么区别?它们在所有主要操作系统中都是相同的吗? 多播地址 …

您引用的描述是用于多播地址的。您的测试代码不使用多播地址。因此,适用不同的描述(来自同一来源):

SO_REUSEPORT SO_REUSEPORT是大多数人所期望的SO_REUSEADDR。基本上,SO_REUSEPORT允许您将任意数量的套接字绑定到--完全是--相同的源地址和端口--只要all以前绑定的套接字在绑定之前也设置了SO_REUSEPORT。…

您的测试代码证实了这一点。

票数 3
EN

Stack Overflow用户

发布于 2019-05-13 20:40:55

多好的黑客啊!它只是蜜蜂引起的。但是,使用SO_REUSEADDR而不是SO_REUSEPORT仍然存在问题。我认为后者可以工作大部分基于*nix的OSes。但是一旦你陷入了困境,摆脱这种情况并不容易,如果你之前没有读过答案,特别是在Mac上。

当然,在使用套接字时,您知道端口号。打开终端,执行以下命令。

代码语言:javascript
复制
lsof -i:<Port used by you>

然后,它为您带来了一条包括PID在内的线路。只需使用-9关闭它,然后通过SO_REUSEPORT更改代码。就这样!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32661091

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档