启用非阻塞套接字 [英] Enable non-blocking socket

查看:209
本文介绍了启用非阻塞套接字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经写在C / C服务器++。
我设置了包装器的连接如下:

I have a server written in C/C++. I set the wrapper for the connection as follow:

    //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

我的目标是使非阻塞套接字模式。
我一直试图做的的fcntl(retv,F_SETFL,O_NONBLOCK); 像Beej说明书上说的,但我收到错误消息: [接受]资源暂时不可用
一种解决的问题是使用在选择功能,但我已经用它在recvtimeout功能,总是喜欢Beej导游说。

My goal is to enable the non-blocking socket mode. I've tried to do fcntl(retv, F_SETFL, O_NONBLOCK); like Beej manual said, but I receive the error: [accept] Resource temporarily unavailable A solution to this problem is using the select function, but I already use it in the recvtimeout function, always like Beej guide said.

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

So, I don't know how to solve this problem to enable the non-blocking socket mode.

推荐答案

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

You get the error because the socket is non-blocking.

无论而你得到的错误(检查你做一个繁忙的循环错误号接受收益 1 对于任何一个 EWOULDBLOCK EAGAIN )。另外,建议解决方案是使用选择时看到插座是可读的,那么你可以调用接受

Either you do a busy loop while you get that error (check errno when accept returns -1 for either EWOULDBLOCK or EAGAIN). The other and recommended solution is to use select to see when the socket is readable, then you can call accept.

编辑:如何与做选择

您需要有一个事件循环处于较高的水平,来检查,如果监听套接字,或连接的插座上,可以读出。如果监听套接字是可读的,那么你可以接受一个新的连接,如果连接插座可读的,那么你可以从中读出。

You need to have an event-loop at a higher level, that checks if the listening socket, or the connected socket(s), can be read from. If the listening socket is readable then you can accept a new connection, and if the connected sockets are readable then you can read from them.

是这样的:

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;
        }
    }
}

如果您有多个连接的插座,把它们放在一个简单的链表,并添加/检查它们在一个循环中。当它们被关闭从列表中删除。

If you have multiple connected sockets, put them in a simple linked list and add/check them in a loop. Remove from list when they are closed.

这篇关于启用非阻塞套接字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆