gpt4 book ai didi

c - 启用非阻塞套接字

转载 作者:太空宇宙 更新时间:2023-11-04 05:43:54 24 4
gpt4 key购买 nike

我有一个用 C/C++ 编写的服务器。我为连接设置包装器如下:

    //START WRAPPER
void Server::init_address(int port)
{
memset(&(this->serv_addr), 0, sizeof(this->serv_addr));
this->serv_addr.sin_family = AF_INET;
this->serv_addr.sin_port = htons(port);
this->serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
}


int Server::w_socket()
{
int retv;
retv = socket(PF_INET, SOCK_STREAM, 0);
//FIXME
//fcntl(retv, F_SETFL, O_NONBLOCK);
if(retv == -1)
{
std::string err_msg(strerror(errno));
err_msg = "[socket] " + err_msg;
throw err_msg;
}
else
{
int reuse_opt = 1;

if(setsockopt(retv, SOL_SOCKET, SO_REUSEADDR, &reuse_opt, sizeof(int))==-1)
{
perror("setsockopt error");
exit(1);
}
return retv;
}
}

void Server::w_bind()
{
int retv;
retv = bind(this->sock_fd,
(struct sockaddr*) &(this->serv_addr),
sizeof(this->serv_addr));

if(retv == -1)
{
std::string err_msg(strerror(errno));
err_msg = "[bind] " + err_msg;
throw err_msg;
}
}

void Server::w_listen()
{
int retv;
retv = listen(this->sock_fd, 3);
if (retv == -1)
{
std::string err_msg(strerror(errno));
err_msg = "[listen] " + err_msg;
throw err_msg;
}
}

int Server::w_accept(struct sockaddr_in* client_addr)
{
int retv;
int socklen = sizeof(sockaddr_in);

retv = accept(this->sock_fd, (struct sockaddr*)client_addr, (socklen_t*)&socklen);
if(retv == -1)
{
std::string err_msg(strerror(errno));
err_msg = "[accept] " + err_msg;
throw err_msg;
}
else
{
return retv;
}
}

int Server::recvtimeout(int s, char *buf, int len, int timeout)
{
fd_set fds;
int n;
struct timeval tv;
// set up the file descriptor set
FD_ZERO(&fds);
FD_SET(s, &fds);
// set up the struct timeval for the timeout
tv.tv_sec = timeout;
tv.tv_usec = 0;
// wait until timeout or data received
n = select(s+1, &fds, NULL, NULL, &tv);
if (n == 0){
return -2; // timeout!
}
if (n == -1){
return -1; // error
}
// data must be here, so do a normal recv()
return recv(s, buf, len, 0);
}
// END WRAPPER

我的目标是启用非阻塞套接字模式。我试过像 Beej 手册中说的那样fcntl(retv, F_SETFL, O_NONBLOCK);,但我收到错误:[accept] Resource temporarily unavailable这个问题的解决方案是使用 select 函数,但我已经在 recvtimeout 函数中使用它了,总是像 Beej 指南说的那样。

所以,我不知道如何解决这个问题来启用非阻塞套接字模式。

最佳答案

您收到错误是因为套接字是非阻塞的。

要么在出现该错误时执行一个繁忙的循环(当 errnoaccept-1 返回 EWOULDBLOCK 时检查 EAGAIN)。另一个推荐的解决方案是使用 select查看套接字何时可读,然后您可以调用 accept .

编辑: 如何使用 select 进行编辑

您需要在更高级别有一个事件循环,用于检查是否可以读取监听套接字或连接的套接字。如果监听套接字是可读的,那么您可以接受新连接,如果连接的套接字是可读的,那么您可以从中读取。

类似于:

for (;;)
{
fd_set readset;

FD_ZERO(&readset);
FD_SET(listening_socket, &readset);
int maxfd = listening_socket;

if (connected_socket >= 0)
{
FD_SET(connected_socket, &readset);
maxfd = max(maxfd, connected_socket);
}

// NULL timeout (5-th argument) means wait until event
select(maxfd + 1, &readset, NULL, NULL, NULL);

if (FD_ISSET(listening_socket, &readset))
{
accept_new_connection(listening_socket);
}

if (connected_socket >= 0 && FD_ISSET(connected_socket, &readset))
{
if (!read_from_socket(connected_socket))
{
close(connected_socket);
connected_socket = -1;
}
}
}

如果你有多个连接的套接字,将它们放在一个简单的链表中并循环添加/检查它们。关闭时从列表中删除。

关于c - 启用非阻塞套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10794999/

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