【问题标题】:Determine between socket and fd在socket和fd之间确定
【发布时间】:2011-09-21 14:49:59
【问题描述】:

在 unix 上 everything is a file 函数 read()write()close() 在 Win32 上不受支持。

我想模仿它,但不知道如何区分 sock 在 WinSocks2 上是 socket 还是 fd

//returns 1 if `sock` is network socket, 
//        0 if `sock` is file desriptor (including stdio, stderr, stdout), ...
//       -1 in none of above
int is_net_socket(int sock)
{
    // ...?
}

这应该像这样工作:

int mysock  = socket(PF_INET, SOCK_STREAM, 0);
int myfd    = _open("my_file.txt", _O_RDONLY);

printf("1: %d    2: %d    3: %d    4:%d\n",
       is_net_socket(mysock),   //1
       is_net_socket(myfd),     //0
       is_net_socket(stdin),    //0
       is_net_socket(stderr));  //0

// should print "1: 1    2: 0    3: 0    4:0"

如何实现is_net_socket 以便在以下情况下使用它:

int my_close(int sock)
{
#if ON_WINDOWS
    switch( is_net_socket(sock) ) {
        case 1: return closesocket(sock);
        case 0: return _close(sock);
        default: //handle error...
    }
#else
    return close(sock);
#endif
}

【问题讨论】:

    标签: c windows sockets winsock winsock2


    【解决方案1】:

    不确定您从哪里了解到 Windows 不允许您将 SOCKET 句柄用作文件 - 正如 Socket Handles 页面上明确说明的那样:

    套接字句柄可以选择是 Windows 套接字 2 中的文件句柄。来自 Winsock 提供程序的套接字句柄可以与其他非 Winsock 函数一起使用,例如 ReadFile、WriteFile、ReadFileEx 和 WriteFileEx。

    无论如何,至于 如何 在 Windows 上区分它们,请参阅函数 NtQueryObject,如果传递给它的句柄是打开的 @987654325,它将返回句柄名称 \Device\Tcp @。阅读此调用返回的结构的“备注”部分。

    请注意,这种方法仅适用于 XP 及更高版本,并且在 Windows 2000 上会失败(我假设它已经足够老,不会影响您。)

    【讨论】:

      【解决方案2】:

      我想你可以使用 select 来查询套接字的状态。

      http://msdn.microsoft.com/en-us/library/ms740141%28VS.85%29.aspx

      我建议将您的文件 desc 和套接字分组到一个结构中。您可以声明一个枚举来判断描述符是文件还是套接字。我知道这可能不像您想要的那样动态,但通常当您创建可移植应用程序时,最好将这些细节抽象出来。

      例子:

      enum type { SOCKET, FILE };
      
      typedef struct
      {
          unsigned int id;
          type dataType;
      } descriptor_t;
      
      int close(descriptor_t sock)
      {
      #if WIN32
          if (sock.dataType == SOCKET)
              return closesocket(sock.id);
          else
              return _close(sock.id);
      #else
          return close(sock.id);
      #endif
      }
      

      【讨论】:

      • 是的,那样操作系统对文件的表示是什么并不重要;您正在自己跟踪它。
      【解决方案3】:

      我怀疑...但我不确定,Windows 上的 fds 和套接字使用单独的命名空间。所以一个socket和一个文件的编号可能是一样的,当你打电话给is_net_socket时不可能知道你在说哪一个。

      尝试打印出 socket 和 fd 编号,看看它们是否同时彼此相同。

      【讨论】:

      • 在 Windows 上,WinSock2(自 NT4 以来的标准)套接字是内核对象句柄(文件对象,AFD 或 Tcp 句柄),这就是您可以在它们上调用标准 ReadFile 和 WriteFile 函数的原因。内核对象的所有句柄都在同一个表中(每个进程)并且不重叠。即使它们碰巧有不同的实现和不同的值,在下一个版本中总是会改变。句柄值应被视为不透明。
      • @ChrisSmith:我们在这里谈论的是SOCKET,这不是我上次检查时的HANDLE
      • 如果你查看winsock2.h,就会看到typedef UINT_PTR SOCKET;这一行。 UINT_PTR 包含一个实际的内核句柄。这就是为什么您可以将它与常规文件 IO API 一起使用:否则它将无法工作。出于这个原因,SOCKETs 在文档中有时被称为“套接字句柄”。
      【解决方案4】:

      如果 Windows 'C' 库有 dup(),你可以尝试 dup 它,这对于套接字应该会失败,但对于文件 fd 会成功。所以:

      int is_net_socket(fd)
      {
        return close(dup(fd)) != 0;
      }
      

      警告:未经测试的理论与未经测试的依赖关系;-) 请注意,如果您用完 fd,这将返回误导性结果。另一个副作用是,如果它是一个文件,它将被刷新并更新其目录条目。总而言之,坦率地说,它可能很糟糕。我什至可能自己投反对票。

      【讨论】:

      • 这很好,可惜我真的希望它没有副作用。没有其他想法?这是一个好的开始:)
      • 这应该没有副作用。只关闭打开文件的最后一个打开文件描述符,而不是它的任何文件描述符,应该有副作用。其实我觉得这个方案还是不错的。
      • @R.. 它确实有副作用。我提到的那些发生在 Windows 上。
      • 哇,这真的很糟糕......顺便说一句,我认为你不能对自己的答案投反对票。
      猜你喜欢
      • 2015-08-21
      • 1970-01-01
      • 1970-01-01
      • 2017-10-15
      • 2023-01-19
      • 2015-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多