我正在使用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的成员无效。
哪个(包括调试)表明在数组上创建套接字时没有正确声明,建议?
答案 0 :(得分:3)
你创建/ bind / listen的代码都很好。然后:
new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);
首先,当它运行时你在循环之外,并且i
是7,它超过了套接字数组的末尾,这就是你得到not-a-socket错误的原因。 / p>
其次,accept()
是一个阻塞调用,因此您不能像对accept()
那样在同一个线程上的所有套接字上调用listen
。对于每个端口,您需要在accept()
中具有单独的线程块,或者使用例如端口找出正在进行客户端连接尝试的线程块。 select
(或epoll
- Windows有吗?),然后accept()
该特定套接字上的客户端(但是你仍然需要创建一个线程来处理客户端{ {1}} / read
s和recv
/ write
s或使用send
/ select
找出何时准备好epoll
的输入或输出缓冲区中的更多空间用于传输)。如果您使用read
/ select
,还有一个竞争条件需要警惕 - 监听套接字可能表示已准备好接受客户端连接,但是当您调用epoll
该连接尝试时失败和遗忘,然后如果侦听套接字尚未设置为非阻塞模式,它将挂起,等待另一个客户端连接到该特定套接字。恕我直言,这是一个线程实际上更容易的情况。
我认为使用IO完成端口(你可能想要谷歌)更“Windowsy”,但AFAIK它们完全不可移植。 Winsock不是BSD套接字的完全匹配,但移植或双支持的工作量很小。