gpt4 book ai didi

c++ - 在使用 Poll() 的 TCP 服务器-客户端连接中,我是否需要手动设置事件?我永远不会到达 POLLOUT 写入套接字

转载 作者:行者123 更新时间:2023-11-28 04:17:43 25 4
gpt4 key购买 nike

我在单个 fd 上使用 poll() 在 c 中建立了客户端和服务器之间的连接。我希望客户端在服务器有东西要发送时收到一条消息,反之亦然。

据我所知,poll() 监听文件描述符上的事件。我不清楚这些事件(或事件)是如何触发的,以确定何时在 fd 上发送或接收。

我曾尝试在客户端循环中使用读取和写入(或就此而言发送和接收),但它们会阻塞,所以我也为客户端切换到 poll()。

在客户端,我永远不会到达 }else if (fds[0].revents & POLLOUT) 部分,这意味着套接字永远无法写入。

   //Create - bind - listen to a socket named listeningSocket

struct pollfd fds[1];
fds[0].fd = listeningSocket;
fds[0].events = POLLIN | POLLPRI;


if (poll(fds, 1, 3000)) {
(client_sock = accept(listeningSocket, &client, (socklen_t *) &c));
spdlog::info("Connection accepted");

std::thread thread(&ConnectionHandler::Handle, std::ref(requestHandler), client_sock);
thread.detach();

}

客户端 block


while (true) {
if ((rv = poll(fds, 1, 100) > 0)) {

if (fds[0].revents & POLLIN ){
recv(sockfd, buff, 200, 0);
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));

}
}else if (fds[0].revents & POLLOUT){
puts(buff);
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, sizeof(buff));
break;
}
}


连接时,服务器用 write() 向客户端发送欢迎消息。客户端 recv() 执行此操作,但之后再也没有轮到它直接返回服务器。

我错过了什么吗?当没有要接收的延迟数据时,套接字不应该准备好写入吗?

最佳答案

让我们重新格式化您的 while循环以使其更易于阅读:

while (true)
{
if ((rv = poll(fds, 1, 100) > 0))
{
if (fds[0].revents & POLLIN)
{
recv(sockfd, buff, 200, 0);
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));
}
}
else if (fds[0].revents & POLLOUT)
{
puts(buff);
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, sizeof(buff));
break;
}
}

现在应该很明显为什么你的 POLLOUT block 永远不会执行 - 即 if语句仅在 poll() 时到达返回 <= 0 ,这不是您想要的。

你需要这样的逻辑:

while (true)
{
if ((rv = poll(fds, 1, 100) > 0))
{
if (fds[0].revents & POLLIN )
{
recv(sockfd, buff, 200, 0);
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));
}
else if (fds[0].revents & POLLOUT)
{
puts(buff);
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, sizeof(buff));
break;
}
}
}

当重新格式化回您的原始编码风格时,它看起来像这样:

while (true) {
if ((rv = poll(fds, 1, 100) > 0)) {

if (fds[0].revents & POLLIN ){
recv(sockfd, buff, 200, 0);
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));

} else if (fds[0].revents & POLLOUT){
puts(buff);
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, sizeof(buff));
break;
}
}
}

看到好的格式带来的不同了吗?

也就是说,知道套接字一连接就进入可写状态。所以你的代码很可能在等待服务器的问候语之前发送客户端的问候语。如果您需要等待服务器的问候语才能回复,则必须先实际阅读问候语,例如:

while (true)
{
if ((rv = poll(fds, 1, 100) > 0))
{
if (fds[0].revents & POLLIN)
{
rv = recv(sockfd, buff, 200, 0);
if (rv <= 0) break;
printf("From Server : %.*s", rv, buff);

if (/* the complete greeting has been read */) // MAY take multiple reads!
{
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, strlen(buff));
break;
}
}
}
}

注意没有必要处理POLLOUT使用阻塞套接字时。但是,如果您改用非阻塞套接字,则您有责任检查是否 write()失败并显示 EWOULDBLOCK错误,如果是,则缓冲您尝试发送失败的数据以及任何后续数据,直到 POLLOUT被报告,然后你可以发送缓冲数据(继续处理 EWOULDBLOCKPOLLOUT )直到缓冲区为空。只有这样,您才能在不处理 POLLOUT 的情况下通过套接字发送新数据。再次直到一个新的EWOULDBLOCK报错。例如:

int sendData(int fd, void *data, int len)
{
char *pdata = (char *) buff;

if (/* fd's buffer is empty */)
{
while (len > 0)
{
int rv = send(fd, pdata, len, 0);
if (rv < 0)
{
if (errno != EWOULDBLOCK)
return rv;
break;
}

pdata += rv;
len -= rv;
}
}

if (len > 0)
{
// add pdata up to len bytes to fd's buffer...
}

return 0;
}

...

while (true)
{
if ((rv = poll(fds, 1, 100) > 0))
{
if (fds[0].revents & POLLIN)
{
rv = recv(sockfd, buff, 200, 0);
if (rv <= 0) break;
printf("From Server : %.*s", rv, buff);

if (/* the complete greeting has been read */) // MAY take multiple reads!
{
strcpy(buff, "HELLO WORLD");
sendData(sockfd, buff, strlen(buff));
}
}

if (fds[0].revents & POLLOUT)
{
char *pdata = ...; // fd's buffer data
int len = ...; // fd's buffer length
int sent = 0;

while (len > 0)
{
rv = send(fd, pdata, len, 0);
if (rv < 0)
break;

pdata += rv;
len -= rv;
sent += rv;
}

if (sent > 0)
{
// remove sent bytes from fd's buffer...
}
}
}
}

然后你可以使用sendData()任何时候你需要发送任何数据到fd ,而不是调用 write()/send()直接。

关于c++ - 在使用 Poll() 的 TCP 服务器-客户端连接中,我是否需要手动设置事件?我永远不会到达 POLLOUT 写入套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56236188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com