【问题标题】:Create multiple listening sockets创建多个监听套接字
【发布时间】:2014-04-01 01:21:16
【问题描述】:

我正在使用 winsocks 并且正在编写 IDS/Honeypot,这只是其中的一小部分,因为目前我希望服务器侦听多个套接字 (7) 并接受连接,但是我'我尝试使用数组(和侦听器等)动态创建套接字,但我仍然遇到问题 - 我已经尝试了多种方法,但到目前为止,我所做的只是让它在一个套接字上成功工作,并监听所有套接字,但不接受它们。

所以,这是我最后一次尝试,但不确定,也许我需要使用线程或以不同的方式声明套接字?

到目前为止,在这个小测试代码中,我想要:

初始化服务器 监听所有 7 个端口(1111,2222 ...等) 接受其中任何一个的传入连接 在客户端/服务器上显示两条消息 断开连接 并继续

我知道这有点草率,但这是到目前为止的代码,我想你可以看到我的目标:

#include <iostream>
#include <winsock2.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")  

int main()
{
    std::cout<<"Honeypot server [test #1] by Dreamwalker"<<std::endl;
    WSADATA wsa;
    SOCKET s[7] , new_socket[7];
    struct sockaddr_in server , client;
    int c, port[7] = {1111,2222,3333,4444,5555,6666,7777};
    char *message;

    std::cout<<"\nInitialising Winsock and other components...";
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        std::cout<<"Failed. Error Code :"<<WSAGetLastError()<<std::endl;
        return 1;
    }


    //!IMPORTANT: create multiple new sockets on different ports
    int i = 0;
    for( i = 0; i < 7; i++)
    {

     //Create socket
    if((s[i] = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
    {
        std::cout<<"Could not create socket : "<< WSAGetLastError()<<std::endl;
    }    

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( port[i] );

    //Bind
    if( bind(s[i] ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
    {
        std::cout<<"Bind failed with error code : "<< WSAGetLastError()<<std::endl;
    }


   /*!ALL CREATION CHECKING DONE, now create multiple sockets on the server
   and listen for connections*/

    c = sizeof(struct sockaddr_in);
    listen(s[i] , SOMAXCONN);

    }

     ///ALL INITIALIZED
    std::cout<<"DONE!"<<std::endl;

    //Listen/accept incoming connections  
    std::cout<<"Now listening for connections"<<std::endl;

    new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);

      if (new_socket[i] == INVALID_SOCKET)
      {
        std::cout<<"accept failed with error code : "<< WSAGetLastError()<<std::endl;
      }

    //Accepted connection
      else{
    std::cout<<"Someone has connected to this machine!"<<std::endl;
    message = "Hello Client , I have received your connection.\n";
    send(new_socket[i] , message , strlen(message) , 0);
    closesocket(s[i]);
      }

      std::cout<<"FINISHED"<<std::endl;

    WSACleanup();
    getchar();
    return 0;
}

现在它也抛出了运行时错误:

WSAENOTSOCK
10038

Socket operation on nonsocket.
An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket,

或者对于 select,fd_set 的成员无效。

哪个(包括调试)表明在数组上创建时未正确声明套接字,建议?

【问题讨论】:

    标签: c++ sockets


    【解决方案1】:

    您创建/绑定/侦听的代码都很好。那么:

    new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);
    

    首先,当它运行时,你已经在循环之外,i 是 7,它超过了套接字数组的末尾,这就是你得到 not-a-socket 错误的原因。

    其次,accept() 是一个阻塞调用,因此您不能像为listen 那样从同一线程的所有套接字上调用accept()。您需要在accept() 中为每个端口设置一个单独的线程块,或者使用例如找出哪个端口正在进行客户端连接尝试。 select(或epoll - Windows 有吗?),然后accept() 在该特定套接字上创建一个客户端(但是您仍然必须创建一个线程来处理客户端read/recv s 和write/sends 或使用select/epoll 找出何时有输入准备好到read,或输出缓冲区中有更多空间用于传输)。如果您使用select/epoll,还有一个需要注意的竞争条件 - 侦听套接字可能表示准备好接受客户端连接,但是当您调用accept() 时,连接尝试失败并被遗忘,那么如果侦听套接字尚未设置为非阻塞模式,它将挂在那里等待另一个客户端连接到该特定套接字。恕我直言,这是线程实际上更容易的情况。

    我认为使用 IO 完成端口(您可能想要谷歌)更“Windowsy”,但 AFAIK 它们完全不可移植。 Winsock 与 BSD 套接字并不完全匹配,但移植或双支持工作量很小。

    【讨论】:

    • 如果您不打算使用多个线程,最好使用ioctlsocket(.., FIONBIO, ..) 将套接字置于非阻塞模式(参见msdn.microsoft.com/en-us/library/windows/desktop/…)。然后,每当像accept 这样的调用会导致等待时,它都会返回WSAEWOULDBLOCK
    • @MicroVirus:非常正确...我刚刚在编辑中提到了这一点,但是拥有更多特定于 Windows 的详细信息和链接真是太好了。干杯。
    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 2021-12-05
    • 2012-09-26
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 2022-11-10
    相关资源
    最近更新 更多