我想获取客户端IP地址或主机名。 我正在使用VS6.0& Windows 7旗舰版VS2010。
服务器上的
CreateNamedPipe(...)
如下:
SECURITY_ATTRIBUTES sa = {0};
hPipe = CreateNamedPipe(
_T("\\\\.\\pipe\\AnonymousPipe"), // pipe name
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
0xD000,
0xD000,
NMPWAIT_USE_DEFAULT_WAIT,
&sa);
if (hPipe == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
return -1;
}
fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
printf("Client connected, creating a processing thread.\n");
// Get Information Of Connected Client.
// Client Ip Address or Hostname.
}
如何检测连接到服务器的客户端?
我可以使用netstat
cmd行查看服务器和客户端之间的连接。
netstat -an|find "445"
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING
TCP 0.0.0.0:445 192.168.125.115:4124 ESTABLISHED
TCP 0.0.0.0:445 192.168.125.192:4882 ESTABLISHED
字符串“192.168.125.115”&“192.168.125.192”是我的目标。 但我找不到在VS6.0中以编程方式检测连接的客户端IP的方法。
有人告诉我,使用GetNamedPipeClientComputerName()来解决这个问题。但
GetNamedPipeClientComputerName()
Minimum supported client Windows Vista [desktop apps only] Minimum supported server Windows Server 2008 [desktop apps only]
许多客户仍在使用Windows XP。
我已经搜索了很多来解决这个问题,但我找不到代码描述。
感谢所有观众。
答案 0 :(得分:1)
评论中已经回答的问题GetNamedPipeClientComputerName
可用于此。它可以从Windows Vista获得。如果想在xp上使用它也可以通过下一个方式实现:
ULONG AltGetNamedPipeClientComputerName(HANDLE Pipe, PWSTR ClientComputerName, ULONG ClientComputerNameLength)
{
static const char AttributeName[] = "ClientComputerName";
if (HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL))
{
IO_STATUS_BLOCK iosb;
NTSTATUS status = NtFsControlFile(Pipe,
hEvent,
NULL,
NULL,
&iosb,
FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,
(void*)AttributeName,
sizeof(AttributeName),
ClientComputerName,
ClientComputerNameLength*sizeof(WCHAR));
if (status == STATUS_PENDING)
{
WaitForSingleObject(hEvent, INFINITE);
status = iosb.Status;
}
CloseHandle(hEvent);
return status == STATUS_NOT_FOUND ? ERROR_PIPE_LOCAL : RtlNtStatusToDosError(status);
}
return GetLastError();
}
这是一般的GetNamedPipeClientComputerName
如何实现内部的。但是如果我们使用同步管道(如此创建没有FILE_FLAG_OVERLAPPED
),我们可以简化功能 - 不需要创建事件 - NtFsControlFile
永远不会返回STATUS_PENDING
同步句柄。
ULONG AltGetNamedPipeClientComputerNameSync(HANDLE Pipe, PWSTR ClientComputerName, ULONG ClientComputerNameLength)
{
static const char AttributeName[] = "ClientComputerName";
IO_STATUS_BLOCK iosb;
NTSTATUS status = NtFsControlFile(Pipe,
hEvent,
NULL,
NULL,
&iosb,
FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,
(void*)AttributeName,
sizeof(AttributeName),
ClientComputerName,
ClientComputerNameLength*sizeof(WCHAR));
return status == STATUS_NOT_FOUND ? ERROR_PIPE_LOCAL : RtlNtStatusToDosError(status);
}
如果我们使用异步管道,从另一方面 - 我们可以而不是在FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE
完成时等待,但是像处理异步的其他请求一样处理异步
一个非常重要的注意事项 - 我们不能在此使用DeviceIoControl
,而只能使用NtFsControlFile
- 这是因为DeviceIoControl
内部检查dwIoControlCode
以及FILE_DEVICE_FILE_SYSTEM
} NtFsControlFile
另外NtDeviceIoControlFile
。 FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE
(来自wdk)中定义的ntifs.h
为
#define FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
FILE_DEVICE_NAMED_PIPE
DeviceIoControl
致电NtDeviceIoControlFile
,但我们需要NtFsControlFile
。
请注意,这仅适用于服务器端管道端(由CreateNamedPipe
创建),以防客户端是远程的。否则STATUS_NOT_FOUND
将从NtFsControlFile
返回。对此代码进行GetNamedPipeClientComputerName
实施特殊检查并将其转换为ERROR_PIPE_LOCAL