英文:
How exactly does the accept() Function in Winsock work?
问题
我正在学习使用C++和Winsock。
一旦ListenSocket通过listen()开始工作,我应该如何以清晰的方式处理多个连接?
当前,每当建立一个新连接时,它都会被移到ConnectedSocket中,当建立新连接时,它会被覆盖。
//监听和成功报告
result = listen(ListenSocket, 2);
if (result == 0)
{
PRINT("正在监听...")
}
else
{
closesocket(ListenSocket);
PRINT("无法监听")
return;
}
//接受连接
ConnectedSocket = accept(m_Socket, nullptr, NULL);
我的第一个想法是创建一个包含套接字的数组,但我如何知道何时建立了新连接,因为我无法自己编写处理新连接的代码。目前我唯一想到的方法是每次运行我的代码时检查连接的套接字是否无效,然后将其移到数组中(如果它是有效的),这不是一个好的选择,因为当其他客户端尝试同时连接时,其中一个可能会被覆盖。
我相信有更好的方法,不是吗?
英文:
I am learning Winsock with c++ right now.
Once the ListenSocket has started with listen(), how am i supposed to handle more than one connection in a clean way?
Right now, everytime a new connection is established it is moved into the ConnectedSocket, and when a new connectiion is established, it gets overridden.
//Listen & Success Report
result = listen(ListenSocket, int(2));
if (result == 0)
{
PRINT("Listening...")
}
else
{
closesocket(ListenSocket);
PRINT("Failed to Listen")
return;
}
//Accept
ConnectedSocket = accept(m_Socket, nullptr, NULL);
My first Idea was to create an Array that holds the Sockets but how do i know when a new connection has been established, since i don't get to write my own code for handling new connections. The only way i can think of right now is to check everytime i run my code, wether the connected Socket is Invalid or not, and then move it into an Array(if it is valid), which is not a good alternative because when other Clients try to Connect at the same time, one of them might get overriden.
I am sure there is a better way, isn't it?
答案1
得分: 2
任何非平凡的服务器都会像这样循环调用accept
:
while (true) {
SOCKET connected = accept(m_Socket, nullptr, nullptr);
// 对连接的`connected`进行操作
}
请注意,accept
的返回值被分配给了while
循环中的局部变量。
一个典型的“对连接进行操作”的方式可以是创建一个新线程,接收connected
中的套接字的副本。或者,您可以将套接字添加到一个全局集合中,然后使用select
或类似的机制进行轮询。
英文:
Any non-trivial server will call accept
in a loop like so:
while (true) {
SOCKET connected = accept(m_Socket, nullptr, nullptr);
// do something with connected
}
Note that the return value of accept
is assigned to a variable that is local to the while
loop.
A typical "do something" could be to spawn a new thread that receives a copy of the socket in connected
.
Alternatively, you might want to add the socket to a global set that you poll with select
or equivalent mechanism.
答案2
得分: 0
在单线程服务器中,通常将socket
描述符放入容器中,如std::vector<SOCKET>
,然后使用select
或类似的函数等待所有套接字上的事件,同时处理多个套接字的事件。
示例:
std::vector<SOCKET> sockets;
sockets.push_back(m_Socket); // 服务器套接字
fd_set readfds{};
for(auto s : sockets) FD_SET(s, &readfds); // 将套接字放入fd_set
int ready_count = select(0 /*在WinSock中被忽略*/,
&readfds, nullptr, nullptr, nullptr);
// 用于新连接和关闭连接的簿记:
std::vector<bool> closed_sockets(sockets.size());
std::vector<SOCKET> new_sockets;
for(int i = 0; i < ready_count; ++i) {
if(not FD_ISSET(sockets[i], &readfds) { // 未就绪
++ready_count;
continue;
}
// sockets[i] 已准备好读取
if(sockets[i] == m_Socket) {
// 服务器
SOCKET ConnectedSocket = accept(m_Socket, nullptr, NULL);
if(ConnectedSocket == INVALID_SOCKET) {
// 错误
} else {
// 保存此连接
new_sockets.push_back(ConnectedSocket);
}
} else {
// 客户端套接字之一
// 如果从 `socket[i]` 读取指示客户端关闭连接:
closed_sockets[i] = true;
}
}
// 从`closed_sockets`中删除设置为`true`的套接字
// 从`new_sockets`中将新连接添加到`sockets`
英文:
In a single threaded server you typically put the socket
descriptor in a container, like a std::vector<SOCKET>
, and then wait for events on all the sockets using
select
or a similar function that can wait on events on many sockets at the same time.
Example:
std::vector<SOCKET> sockets;
sockets.push_back(m_Socket); // the server socket
fd_set readfds{};
for(auto s : sockets) FD_SET(s, &readfds); // put sockets in the fd_set
int ready_count = select(0 /*ignored in WinSock*/,
&readfds, nullptr, nullptr, nullptr);
// for bookkeeping of new and closed connections:
std::vector<bool> closed_sockets(sockets.size());
std::vector<SOCKET> new_sockets;
for(int i = 0; i < ready_count; ++i) {
if(not FD_ISSET(sockets[i], &readfds) { // not ready
++ready_count;
continue;
}
// sockets[i] is ready to be read
if(sockets[i] == m_Socket) {
// server
SOCKET ConnectedSocket = accept(m_Socket, nullptr, NULL);
if(ConnectedSocket == INVALID_SOCKET) {
// error
} else {
// save this connection
new_sockets.push_back(ConnectedSocket);
}
} else {
// one of the client sockets
// if reading from `socket[i]` indicates that the client
// closed the connection:
closed_sockets[i] = true;
}
}
// Remove sockets set to `true` in `closed_sockets`
// Add new connections to `sockets` from `new_sockets`
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论