如何区分套接字句柄和文件句柄

时间:2018-06-22 00:27:12

标签: sockets winapi handles

我需要检查Windows中进程创建事件中的某些行为,我需要实现一个规则,该规则检查传递给createprocess api调用的startupinfo结构并提取std输入/ std输出处理所创建进程的值。 然后,我必须检查此句柄是否属于tcp套接字。 是否有任何api函数可以帮助我获取有关我拥有的句柄编号的任何信息(无论是文件句柄还是套接字句柄)?

3 个答案:

答案 0 :(得分:0)

使用GetFileType()功能

  

检索指定文件的文件类型。

     

语法

DWORD WINAPI GetFileType( _In_ HANDLE hFile ); 
     

参数

     

hFile [[in]

     

文件的句柄。

     

返回值

     

该函数返回以下值之一。

     

FILE_TYPE_CHAR

     

指定的文件是字符文件,通常是LPT设备或控制台。

     

FILE_TYPE_DISK

     

指定的文件是磁盘文件。

     

FILE_TYPE_PIPE

     

指定的文件是套接字,命名管道或匿名管道。

     

FILE_TYPE_REMOTE

     

未使用。

     

FILE_TYPE_UNKNOWN

     

指定文件的类型未知,或者函数失败

答案 1 :(得分:0)

以@RemyLebeau的答案为基础,我想我是否可以找到一种可靠的方法来将套接字与管道区分开来(GetFileType()无法做到),于是我想到了以下内容:工作,没有明显的缺点。

要点是getsockopt()如果传递的不是套接字,将返回WSAENOTSOCK(= 10038)。因此,此测试本身就足够了,只要传递给它的任何句柄是SOCKET或文件或管道句柄。不要仅仅将其传递给任何旧的HANDLE(有各种各样的句柄),否则可能会根据@HansPassant在下面的第一条评论而感到困惑。

示例代码:

#include <winsock2.h>                   // * before* windows.h (!)
#include <windows.h>
#include <assert.h>
#include <iostream>

int main ()
{
    WSADATA wsa_data;
    int err = WSAStartup (2, &wsa_data);
    assert (err == 0);

    // Pipe

    HANDLE hReadPipe, hWritePipe;
    BOOL ok = CreatePipe (&hReadPipe, &hWritePipe, NULL, 2048);
    assert (ok);

    int opt;
    int optlen = sizeof (opt);
    err = getsockopt ((SOCKET) hReadPipe, IPPROTO_TCP, TCP_NODELAY, (char *) &opt, &optlen);

    if (err)
    {
        DWORD dwErr = GetLastError ();
        std::cout << "Pipe: " << dwErr << std::endl;
    }
    else
        std::cout << "Pipe: OK" << std::endl;

    CloseHandle (hReadPipe);
    CloseHandle (hWritePipe);

    // Socket

    SOCKET skt = WSASocket (AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
    assert (skt != INVALID_SOCKET);

    optlen = sizeof (opt);
    err = getsockopt (skt, IPPROTO_TCP, TCP_NODELAY, (char *) &opt, &optlen);

    if (err)
    {
        DWORD dwErr = GetLastError ();
        std::cout << "Socket: " << dwErr << std::endl;
    }
    else
        std::cout << "Socket: OK" << std::endl;

    closesocket (skt);
    return 0;
}

输出:

Pipe: 10038
Socket: OK

编辑:如果您阅读下面的评论,您会发现已经有人在讨论是否可以使该代码相信文件或管道的HANDLE实际上是一个SOCKET。好吧,那不可能。我们之所以知道这一点,是因为ReadFile()WriteFile()之类的功能在文件/管道HANDLE和SOCKET上均能很好地工作,并且如果有可能将两者误用,那就行不通了。

因此,此代码在所有情况下(包括重定向的输出,Remy的代码都将其视为套接字)在所有情况下(a)安全,(b)简单且(c)有效。因此,我推荐它。只要确保先致电WSAStartup(),然后再执行其他操作即可。

感谢@HansPassant和@eryksun为这篇文章做出了重要贡献。

答案 2 :(得分:0)

使用GetNamedPipeInfo(s,NULL,NULL,NULL,NULL)来区分管道和套接字。

127.0.0.1 - - [15/Feb/2013 10:52:22] "GET /index.html HTTP/1.1" 200