如何在 TCP 侦听器中处理异步发送和接收
How to handle asynchronous send and receive in TCP listener
我是套接字编程的新手。我正在尝试制作一个可以处理多个连接的 TCP 侦听器。
我发现这个例子似乎很有用。
此代码的问题在于,它仅在收到数据时才将数据发送到连接的客户端。我想异步将数据发送到连接的客户端。
我看到select()
函数永远阻止代码,直到事件到达套接字。
我想在函数select()
中放置延迟(而不是NULL
),以便它每隔几微秒超时一次,并且程序将能够发送数据(如果有的话)。在线路if (buffer[0] > 0)
问题是:有没有更好的方法来做我想做的事?我可以用其他方式强制select()
超时吗?
char buffer[1025];
是从另一个线程填充的全局数组。下面的while(TRUE)
正在另一个线程上运行。
while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL ,
//so wait indefinitely
struct timeval timeout;
timeout.tv_usec = 10000;
activity = select( max_sd + 1 , &readfds , NULL , NULL , &timeout);
if ((activity < 0) && (errno!=EINTR))
{
cout << "select error" << endl;
}
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket,
(struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//send new connection greeting message
if( send(new_socket, message, strlen(message), 0) != strlen(message) )
{
perror("send");
}
puts("Welcome message sent successfully");
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %dn" , i);
break;
}
}
}
if (buffer[0] > 0)
{
sd = client_socket[0];
send(sd , buffer , strlen(buffer) , 0 );
}
//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&address ,
(socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d n" ,
inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//set the string terminating NULL byte on the end
//of the data read
buffer[valread] = ' ';
send(sd , buffer , strlen(buffer) , 0 );
}
}
}
}
此代码的问题在于,它仅在收到数据时才将数据发送到连接的客户端。
这是因为原始代码实现了请求/响应服务器 - 在这种情况下,它专门是一个回显服务器。
我想异步将数据发送到连接的客户端。
您可能希望首先枚举服务器开始异步发送数据的条件/触发器。我即兴编造的一个例子是多回声服务器。一旦这样的服务器从客户端收到一个字符串,它就会回显 3 次,每次回显由(比如)1 秒分隔。
在这种情况下,可以选择超时来中断等待,并且可以修改"if buffer[0]> 0"检查以发送任何挂起的回显。
问题是:有没有更好的方法来做我想做的事?我可以用其他方式强制 select() 超时吗?
手册页表示还有第三种方式来突破选择,即安排要传递的信号。但是,我认为,这应该用于处理传递给服务器程序的信号,并且只用于处理异步 IO 的选择超时。更准确地说,我已经看到生产级服务器在其异步循环中使用 epoll/kqueue(更好的替代方案)超时。所以,你的方法似乎很合理。
对于单线程服务器来说,围绕对select
或poll
的调用有一个"计时器"列表是很常见的 - 必须在特定时间完成的事情。当代码不需要执行任何操作时,请检查计时器列表指示需要执行某些操作的时间,并调用select
或poll
将该时间长度指定为超时。
所以你的循环往往看起来像这样:
- 检查计时器列表并计算我们需要做某事的时间。
- 调用
select
或poll
将其指定为超时。 - 如果我们发现任何套接字已准备好进行操作,请执行这些操作。
- 如果需要执行任何计时器,请执行它们。
- 转到步骤 1。
如果您需要定期执行某些操作,请设置一个初始计时器以在第一次执行该操作。然后让计时器的执行代码设置一个新的计时器以再次执行该操作。
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- libcurl :C++处理多个异步请求
- 如何使用从处理程序调度的最终回调将响应异步返回给调用方on_read?
- 某些 boost::asio 异步函数是否将处理程序连接到操作,以便处理程序被触发一次?
- grpcc++异步服务器示例,在处理状态下是否需要互斥
- 窗口上信号处理程序的异步安全写入函数
- 异步操作的 Asio 处理程序在其同步对应项正常工作时不会调用
- 如何处理异步函数中的异常UWP应用程序getFileFrompathAsync(path);
- 如何在 TCP 侦听器中处理异步发送和接收
- 异步处理设备的高级线程用法
- 使用 boost::beast 异步处理流式 HTTP
- 使用多线程处理的异步请求
- boost::bind with member functions(作为boost::asio异步写入处理程序)
- C++-如何为同时/异步处理对文件进行分块
- 如何在Windows中进行正确的顺序异步消息处理
- 接受Boost ASIO异步处理程序
- c++中的异步处理
- c++: Boost::asio:在同一个函数中等待异步处理程序
- 如何在c++中异步处理本地socket上的https请求响应
- 刷新boost::asio中的所有异步处理程序