BSD(MacOSX和OpenBSD)和Linux(Ubuntu)的套接字行为不同

BSD(MacOSX和OpenBSD)和Linux(Ubuntu)的套接字行为不同,c,linux,sockets,bsd,C,Linux,Sockets,Bsd,我最初在mac上写了一个中间人/代理服务器。实际上,代理创建套接字并等待连接,然后连接到另一个应用程序。这在OSX和OpenBSD中都能完美地工作;然而,当将代理移植到Ubuntu时,它并没有按预期工作 此代理有两个实例正在运行,在两个单独的端口上侦听。在Ubuntu上运行时,所有流量都通过一个端口。当通过fcntl将套接字设置为非阻塞时,我也遇到了一个问题,有时它会因无效参数而失败 我正在使用sys/socket 在这个港口有什么我错过的陷阱吗 编辑: 我认为有两个问题。一个是无效参数,另一个

我最初在mac上写了一个中间人/代理服务器。实际上,代理创建套接字并等待连接,然后连接到另一个应用程序。这在OSX和OpenBSD中都能完美地工作;然而,当将代理移植到Ubuntu时,它并没有按预期工作

此代理有两个实例正在运行,在两个单独的端口上侦听。在Ubuntu上运行时,所有流量都通过一个端口。当通过fcntl将套接字设置为非阻塞时,我也遇到了一个问题,有时它会因无效参数而失败

我正在使用sys/socket

在这个港口有什么我错过的陷阱吗

编辑:

我认为有两个问题。一个是无效参数,另一个是流量被推送到不同的端口

服务1绑定到代理实例1,然后代理实例1绑定回黑盒上的相应服务,从而启动服务2。然而,由于某些原因,在Ubuntu上,它连接到实例1,该实例正在错误的端口上侦听

fcntl的无效参数的编辑解决方案:

找到了为什么我得到了无效的论点,很遗憾,我还有另一个问题。 fcntlfd,cmd,arg

cmd-F_SETFLlong

我传入了一个指向int的指针,而不是long原语

编辑:


只是猜测,但我认为你的问题在于你处理注射插座的方式。我不知道您在//截断代码块中删除了什么,但基本上您所做的是:

// Parent process -- bind & listen on the injection socket
injfd = socket(...);
bind(injfd, ...);
listen(injfd, ...);
...
while (1)
{
    client = wait_for_connection();
    ...
    if (!fork())
    {
        // Each child process
        ...
        if (stuff && FD_ISSET(injfd, &R)) {
            new_socket = accept(injfd);
            ...
        }
        ...
    }
    ...
}
换句话说,您的所有子进程都在侦听同一个注入套接字并尝试接受连接。我不确定这是否是定义良好的行为,但即使在最好的情况下,当一个新连接到达注入端口时,接受连接的过程可能是随机和不可控的。它可以是任何子进程,甚至是父进程


为了控制这种行为,您需要决定谁应该监听注入套接字上的连接。如果只有父级应该侦听,那么只有父级应该对其调用accept或将其作为参数传递给select。同样,如果只有一个特定的子级应该在侦听,那么只有该子级应该调用accept或将其传递给select。忽略该套接字的所有其他进程应尽早关闭它,例如在fork返回后立即关闭,以避免泄漏文件描述符。

结果表明,SO_REUSEADDR socket选项是问题所在。我删除了我设置的插座选项,一切都解决了


带我找到解决办法

非阻塞无效参数听起来像某种bug。您可能应该发布一些相关的代码。添加的代码用于引用发布您的实际代码,而不是起始点引用。哪个对fcntl的调用失败了,调用F_GETFL或F_SETFL的调用?F_SETFL就是失败的地方,但奇怪的是,不是一直都失败。你真的关心编写这个低级套接字代码吗?如果没有,请查看或。我没有在愤怒中使用libev,但我使用libevent做了一些事情,比如你正在做的事情,我发现它非常有效。避免那个备忘录也会有帮助。这是我对这个问题的最初想法,我认为这与非阻塞无效参数问题有关。所以早些时候我移除了fork,我仍然遇到了一个问题,所有的流量都集中在一个端口上,而不是应该集中在两个端口上,以及它在基于BSD的系统上是如何工作的。难以置信。
// Parent process -- bind & listen on the injection socket
injfd = socket(...);
bind(injfd, ...);
listen(injfd, ...);
...
while (1)
{
    client = wait_for_connection();
    ...
    if (!fork())
    {
        // Each child process
        ...
        if (stuff && FD_ISSET(injfd, &R)) {
            new_socket = accept(injfd);
            ...
        }
        ...
    }
    ...
}