Based on libevent, libuv and Android logoff, socket programming continues to evolve

Source: Internet
Author: User
Tags epoll

In my recent work on websocket porting, we need to implement the underlying socket read and write. I have written a set based on synchronous read, libevent, libuv, and Android logoff, and I have learned a lot from it.

1) Synchronous read/write Blocking

At first, synchronous blocking reading and writing was adopted to quickly verify the completeness of the Upper-layer websocket protocol. The advantage is that it is easy to implement. The disadvantage is that the efficiency is not high and the thread resources cannot be used well. The connection establishment method is similar. The main difference is how to read and write data, let's take a look at the one shared by several methods:

 

    int n = 0;    struct sockaddr_in serv_addr;    event_init();    if((mSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){        //TODO error        return;    }    memset(&serv_addr, '0', sizeof(serv_addr));    serv_addr.sin_family = AF_INET;    serv_addr.sin_port = htons(url.port());    if(inet_pton(AF_INET, url.host().utf8().data(), &serv_addr.sin_addr)<=0){        return;    }    if( connect(mSockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){        return;    }

Because it is a client, it is relatively simple. Of course, DNS resolution is missing. Then, we need to monitor the read data. Because the read is blocked synchronously, We need to continuously read/Recv in the Loop:

 

 

    while (1) {        ssize_t result = recv(fd, buf, sizeof(buf), 0);        if (result == 0) {            break;        } else if (result < 0) {            perror("recv");            close(fd);            return 1;        }        fwrite(buf, 1, result, stdout);    }

The disadvantage is obvious. This thread needs to be polling continuously. Of course, this is a subprogram, and it will not be so hasty in the formal code.

 

2) libevent

The above improvement method is to process read data in asynchronous non-blocking mode. in Linux, epoll is generally used for asynchronous event listening, libevent is a C library that encapsulates asynchronous events on epoll or other platforms. Therefore, it is easier to Implement Asynchronous non-blocking read/write based on libevent and cross-platform. The first step of refactoring is to set socketfd to non-blocking:

 

static int setnonblock(int fd){    int flags;    flags = fcntl(fd, F_GETFL);    if (flags < 0){        return flags;    }    flags |= O_NONBLOCK;    if (fcntl(fd, F_SETFL, flags) < 0){        return -1;    }    return 0;}

Then you need to maintain the event loop in a separate thread and add the read event listener:

 

 

static void* loopListen(void *arg){    SocketStreamHandle *handle = (SocketStreamHandle *)arg;    struct event_base* base = event_base_new();    struct event ev_read;    handle->setReadEvent(&ev_read);    setnonblock(handle->getSocketFD());    event_set(&ev_read, handle->getSocketFD(), EV_READ|EV_PERSIST, onRead, handle);    event_base_set(base, &ev_read);    event_add(&ev_read, NULL);    event_base_dispatch(base);}
    pthread_t pid;    pthread_create(&pid, 0, loopListen, this);

Then process the data read in the onread method:

 

static void onRead(int fd, short ev, void *arg){    while(true){        char *buf = new char[1024];        memset(buf, 0, 1024);        int len = read(fd, buf, 1024);        SocketStreamHandle *handle = (SocketStreamHandle *)arg;        if(len > 0){            SocketContext *context = new SocketContext;            context->buf = buf;            context->readLen = len;            context->handle = handle;            WTF::callOnMainThread(onReadMainThread, context);            if(len == 1024){                continue;            }else{                break;            }        }else{            if(errno == EAGAIN || errno == EWOULDBLOCK){                return;            }else if(errno == EINTR){                continue;            }            __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "onCloseMainThread, len:%d, errno:%d", len, errno);            WTF::callOnMainThread(onCloseMainThread, handle);            event_del(handle->getReadEvent());        }    }}

Here we pay more attention to the following:

 

1) when a Buf cannot be fully read, it needs to be read again in a loop.

2) When read to 0, it indicates that the socket is closed. In this case, you need to delete the event listening. Otherwise, the CPU will be 100%

3) When read to-1, it is not completely an error. For example, errno = eagain | errno = ewouldblock indicates that it is temporarily unreadable and will be read later. Errno = eintr indicates the system was interrupted and should be re-viewed

4) onread is called by a thread dedicated to event listening by libevent, so sometimes it is necessary to return to the main thread, such as: WTF: callonmainthread (onreadmainthread, context ); pay attention to the synchronization between multiple threads.

3) libuv

Libuv goes further in libevent. It not only has event loop, but also covers various socket operations, so the code will be more concise, such as the initial connection creation and loop creation:

 

    uv_loop_t *loop = uv_default_loop();    uv_tcp_t client;    uv_tcp_init(loop, &client);    struct sockaddr_in req_addr = uv_ip4_addr(url.host().utf8().data(), url.port());    uv_connect_t *connect_req;    connect_req->data = this;    uv_tcp_connect(connect_req, &client, req_addr, on_connect);    uv_run(loop);

Create a read listener in on_connect:

 

 

static void* on_connect(uv_connect_t *req, int status){    SocketStreamHandle *handle = (SocketStreamHandle *)arg;    uv_read_start(req->handle, alloc_buffer, on_read);}

On_read is similar to the previous one. Therefore, libuv is the most powerful, greatly omitting socket-related development.

 

4) Android Logoff

Android provides an event Loop Mechanism and can listen to FD. Therefore, if you use Android logoff, you can skip the dependency on third-party Lib. In addition, Android is also an encapsulation of epoll. In this case, it is worth trying to use the android native looper for event logoff. The socket connection is the same as that at the beginning. The key is to create a Logoff:

 

static void* loopListen(void *arg){    SocketStreamHandle *handle = (SocketStreamHandle *)arg;    setnonblock(handle->getSocketFD());    Looper *looper = new Looper(true);    looper->addFd(handle->getSocketFD(), 0, ALOOPER_EVENT_INPUT, onRead, handle);    while(true){        if(looper->pollOnce(100) == ALOOPER_POLL_ERROR){            __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "ALOOPER_POLL_ERROR");            break;        }    }}

The code is simple and can be used in detail to view the <utils/lols. h> API.

 

To sum up, if it is implemented on Android, it can be directly based on the native logoff, and cross-platform can be based on libuv. In short, avoid synchronization blocking, because this will lead to complicated and inefficient thread design.

There are similar concepts in Java. For more information, see the previous blog:

 

Extract the classic NiO architecture network server from jetty, tomcat, and Mina (1)
Extract the classic NiO architecture network server from jetty, tomcat, and Mina (2)
Extract the classic NiO architecture network server from jetty, tomcat, and Mina (3)

 

 

 

 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.