【问题标题】:SOCKET connection problems in a service on WIndows 2012WINdows 2012 服务中的 SOCKET 连接问题
【发布时间】:2015-11-07 09:51:21
【问题描述】:

我继承了一个 C++/Windows 项目,其中我们有一个 SNMP 扩展代理(由 snmp 服务加载)。在代理内部,我们正在创建一个简单的 TCP 服务器,我们的客户端应用程序连接到该服务器并为其提供 SNMP 查询/陷阱等数据。这一切似乎在 Windows 2008 上运行良好。但是,在 Windows 2012 上,客户端不能再连接到在代理内部运行的服务器(在 SNMP 服务中)。 connect() 失败,错误 10013。

我的服务器代码如下所示:

fd_set  master_set;
fd_set  readfds;
SOCKET  listener;

WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
    OutputDebugStringA("WSAStartup failed\n");
    return -1;
}
FD_ZERO(&master_set);
FD_ZERO(&readfds);

//----------------------
// Create a SOCKET for listening for
// incoming connection requests.

listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listener == INVALID_SOCKET) {
    OutputDebugStringA("socket failed with error:\n");
    return -1;
}
int reuse_addr = 1;

setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse_addr, sizeof(reuse_addr));
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service = { 0 };
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(27015);

if (bind(listener, (SOCKADDR *)& service, sizeof(service)) == SOCKET_ERROR)
{
    printf("bind failed with error: %d \n", WSAGetLastError());
    closesocket(listener);
    return -1;
}

if (listen(listener, 5) == SOCKET_ERROR)
{
    OutputDebugStringA("listen failed with error\n");
    closesocket(listener);
    return -1;
}

u_long NonBlock = 1;
if (ioctlsocket(listener, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
    OutputDebugStringA("ioctlsocket() failed with error\n");
    return -1;
}


FD_SET(listener, &master_set);

timeval timeout;
timeout.tv_sec = 3;
timeout.tv_usec = 0;

printf("Started Server on port %d\n", 27015);

for (;;)
{
    readfds = master_set;

int ret = select(0, &readfds, NULL, NULL, &timeout);

    if (ret == 0)
    {
        // Time out // Check if we need to shutdown

            continue;
    }

if (ret < 0)
    {
        printf("Error in Socket select\n");
        return -1;
    }

    for (int i = 0; i < readfds.fd_count; i++)
    {
        SOCKET xfd = readfds.fd_array[i];

        if (xfd == listener)
        {
            // New Connection.
            SOCKET new_fd = HandleNewConnection(listener);
            if (new_fd == -1)
            {
                printf("Error Accepting new connection");
                continue;
            }
            FD_SET(new_fd, &master_set);
            printf("Accepted new Connection\n");
            continue;
        }
        else
        {
            if (!HandleIncomingData(xfd))
            {
                closesocket(xfd);
                FD_CLR(xfd, &master_set);
                continue;
            }
        }
    }
}

SOCKET HandleNewConnection(SOCKET listener)
{
  SOCKET newfd = accept(listener, (sockaddr*)NULL, (int*)NULL);
  u_long NonBlock = 1;
  ioctlsocket(newfd, FIONBIO, &NonBlock);
  return newfd;
  }

  bool HandleIncomingData(SOCKET fd)
  {
  char buffer[16] = { 0 };
  int recv_bytes = -1;
  if ((recv_bytes = recv(fd, buffer, 16, 0)) <= 0)
  {
    printf("Connection Closed/ Error in Recieving");
    return false;
  }

  printf("recieved %d bytes\n", recv_bytes);
  return true;
}

选择继续每 3 秒超时一次,没有任何连接被接受。

这是我尝试过的所有方法(没有一个有效):

  1. 尝试在特定用户帐户中运行服务。
  2. 服务器在单独的线程中运行,我提供了一个带有 NULL DACL 的 SECURITY_ATTRIBUTE 以查看是否存在安全问题。
  3. 尝试了不同的端口。
  4. 在单独的普通应用程序中尝试了相同的服务器代码。客户端可以连接到此应用程序。
  5. 从代理启动示例服务器应用程序时,客户端无法连接到它。
  6. Windows 防火墙已关闭,我没有安装任何会阻止此类连接的防病毒软件。
  7. 从外部检查连接并在 Wireshark 中观察到 TCP SYN 数据包确实到达但没有响应。
  8. 在 Process Explorer TCP/IP 属性中观察到 SNMP 服务确实有一个 TCP 套接字在 127.0.0.1:27015 上侦听。

为了快速测试,我只是在 telnet 到 27015 端口。

我的问题是:

  1. 我缺少的服务器代码是否有明显错误?
  2. Windows 2012 中是否存在一些不允许服务接受此类 TCP 连接的安全限制?
  3. 还有其他提示、cmets、输入吗?

谢谢,

【问题讨论】:

  • 不要直接使用readfds结构,使用FD_ISSET宏来检查一个socket是否在集合中。此外,不要以这种方式遍历集合,而是保存已连接套接字的列表并仅检查它们。特别是因为在尝试处理套接字之前,您实际上并没有检查套接字是否有事件。
  • 您是否考虑过查找 Winsock 错误 10013?
  • 感谢 cmets。是的,我查找了 10013,即 WSAEACCESS: Permission denied。试图以访问权限禁止的方式访问套接字。一个例子是在没有使用 setsockopt(SO_BROADCAST) 设置广播权限的情况下将广播地址用于 sendto。
  • WSAEACCES 错误的另一个可能原因是,当调用绑定函数时(在带有 SP4 的 Windows NT 4.0 和更高版本上),另一个应用程序、服务或内核模式驱动程序被绑定到同一个地址独家访问。这种独占访问是带有 SP4 及更高版本的 Windows NT 4.0 的新功能,通过使用 SO_EXCLUSIVEADDRUSE 选项实现。
  • @JoachimPileborg 我也尝试过使用 FD_ISSET()(在我的原始代码中仍然存在)但是对我来说真正的问题是 select() 总是返回 0,这意味着超时(FD_ISSET() 返回 false )。

标签: c++ sockets tcp snmp windows2012


【解决方案1】:

我解决了这个问题。该问题是由于 Windows 服务强化导致的,它不允许来自 snmp 服务(和扩展)的任何 TCP 通信。即使防火墙已关闭,也会强制执行此操作。

https://support.microsoft.com/en-us/kb/2771908

【讨论】:

  • 您能详细说明您是如何解决的吗?有没有办法禁用强化规则?
【解决方案2】:

我可以按照这些步骤解决它(在 http://www-01.ibm.com/support/docview.wss?uid=nas7ba16117761f1f93b86257f73000cff77 中找到)

  1. 以管理员身份登录系统并通过在命令提示符下发出 regedit 打开注册表。
  2. 导航到 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\RestrictedServices\Static\System]。
  3. 找到满足以下几点的值: 一种。 “名称”字符串以“SNMP-”开头。 湾。 “数据”字符串包含“syswow64\snmp.exe”。 C。 “Data”字符串包含“Action=Block”。
  4. 将这些条目的“Action=Block”更改为“Action=Allow”。
  5. 通过发出 net stop MPSSVC 和 net start MPSSVC 重新启动“Windows 防火墙”服务。
  6. 使用 net stop SNMP 和 net start SNMP 重新启动“SNMP Service”服务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多