2011-06-23 36 views
15

在Unix 一切文件的功能read()write()方法,close()不支持在Win32。确定和FD

我想效仿,但不知道如何当sock插座或WinSocks2 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 
} 
+0

人使用_fstat()? – DinGODzilla

回答

3

我怀疑......但我不确定,Windows上的fds和套接字使用单独的名称空间。因此,套接字和文件的编号可能相同,当您拨打is_net_socket时,无法知道您正在谈论的是哪一个。

尝试打印出套接字和fd号码,看看它们是否在同一时间相同。

+0

在Windows上,WinSock2(自NT4以来的标准)套接字是内核对象句柄(File对象,AFD或Tcp句柄),这就是为什么你可以在它们上调用标准的ReadFile和WriteFile函数的原因。内核对象的所有句柄都在同一个表中(每个进程)并且不重叠。即使它们碰巧有不同的实现和不同的值,在下一个版本中也可能会发生变化。处理值应该被视为不透明。 –

+0

@ChrisSmith:我们在这里讨论'SOCKET',这不是我上次检查时的'HANDLE'。 –

+0

如果你看'winsock2.h',有'typedef UINT_PTR SOCKET'这一行。 'UINT_PTR'包含一个实际的内核句柄。这就是为什么您可以将它与常规文件IO API一起使用的原因:否则无法正常工作。出于这个原因,SOCKET有时被称为“套接字句柄”。 –

3

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

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

警告:未经检验的理论或未经测试的依赖;-)请注意,如果你用完了FD的的,这将返回错误的结果。另一个副作用是,如果它是一个文件,它将被刷新并更新其目录条目。总而言之,它可能很糟糕。我甚至可能自己冷静下来。

+0

+1:创造性滥用I/O系统基础! – wallyk

+0

这很好,我真的希望它是副作用免费。没有其他想法?这是开始:) – DinGODzilla

+0

这应该不会有副作用。只关闭打开文件的最后一个打开的文件描述符,而不是任何文件描述符,都应该有副作用。其实我认为这个解决方案相当不错。 –

5

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

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

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

例子:

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 
} 
+0

是的,这样无关乎操作系统对文件的表示是什么;你正在跟踪它自己。 –

9

不知道你在哪里得到的想法,Windows将不会允许您使用SOCKET手柄的文件 - 如Socket Handles页面上明确提出:

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

不管怎么说,作为如何它们之间在Windows上区分,见函数NtQueryObject,这将返回\Device\Tcp一个昵称,如果传递给它的手柄是一个开放的SOCKET。阅读本次调用返回的结构的“备注”部分。

注意,这种方法只适用于XP和起来,将无法在Windows 2000(这我假设是足够大,它不影响你。)

相关问题