Linux非阻塞IO(五)使用poll實現非阻塞的回射伺服器用戶端

來源:互聯網
上載者:User

標籤:style   blog   http   color   io   os   ar   使用   for   

前面幾節我們討論了非阻塞IO的基本概念、Buffer的設計以及非阻塞connect的實現,現在我們使用它們來完成用戶端的編寫。

我們在http://www.cnblogs.com/inevermore/p/4049165.html中提出過,用戶端需要監聽stdin、stdout和sockfd。

這裡需要注意的是

只有緩衝區可寫的時候,才去監聽sockfd和stdin的讀事件。

過去在阻塞IO中,我們總是監聽sockfd的讀事件,因為每當sockfd可讀,我們就去調用使用者的回呼函數處理read事件,在回呼函數中需要使用者手工read緩衝區的資料。 換句話說,接收資料是使用者的責任,poll模型只需要提醒使用者去接收即可。

而在非阻塞IO中,因為poll採用的是水平觸發,如果緩衝區滿了,每次read等於無效操作,那麼資料始終堆積在核心中,poll會不停的被觸發。這在某種程度上等於輪詢。所以我們只在緩衝區可用的情況下監聽sockfd的讀事件。

只有緩衝區可讀的時候,才去監聽sockfd和stdout的寫事件。因為沒有資料可寫,監聽write事件除了不停的觸發poll之外,沒有實際意義。

所以每次執行poll之前,需要重新裝填poll的events數組。

完整的代碼如下:

#include "sysutil.h"#include "buffer.h"int main(int argc, char const *argv[]){    //建立client通訊端    int sockfd = tcp_client(8934);    //調用非阻塞connect函數    int ret = nonblocking_connect(sockfd, "192.168.44.136", 9981, 5000);    if(ret == -1)    {        fprintf(stderr, "Timeout .\n");        exit(EXIT_FAILURE);    }    //將三個fd設定為Non-Blocking    activate_nonblock(sockfd);    activate_nonblock(STDIN_FILENO);    activate_nonblock(STDOUT_FILENO);    buffer_t recvbuf; //sockfd -> Buffer -> stdout    buffer_t sendbuf; //stdin -> Buffer -> sockfd    //初始化緩衝區    buffer_init(&recvbuf);    buffer_init(&sendbuf);    struct pollfd pfd[10];    while(1)    {        //初始化        int ix;        for(ix = 0; ix != 3; ++ix)        {            pfd[ix].fd = -1;            pfd[ix].events = 0;        }        //重新裝填events數組        if(buffer_is_readable(&sendbuf))        {            pfd[0].fd = sockfd;            pfd[0].events |= kWriteEvent;        }        if(buffer_is_writeable(&sendbuf))        {            pfd[1].fd = STDIN_FILENO;            pfd[1].events |= kReadEvent;        }        if(buffer_is_readable(&recvbuf))        {            pfd[2].fd = STDOUT_FILENO;            pfd[2].events |= kWriteEvent;        }        if(buffer_is_writeable(&recvbuf))        {            pfd[0].fd = sockfd;            pfd[0].events |= kReadEvent;        }        //監聽fd數組        int nready = poll(pfd, 3, 5000);        if(nready == -1)            ERR_EXIT("poll");        else if(nready == 0)        {            printf("timeout\n");            continue;        }        else        {            int i;            for(i = 0; i < 3; ++i)            {                int fd = pfd[i].fd;                if(fd == sockfd && pfd[i].revents & kReadEvent)                {                    //從sockfd接收資料到recvbuf                    if(buffer_read(&recvbuf, fd) == 0)                    {                        fprintf(stderr, "server close.\n");                        exit(EXIT_SUCCESS);                    }                 }                                    if(fd == sockfd && pfd[i].revents & kWriteEvent)                    buffer_write(&sendbuf, fd); //將sendbuf中的資料寫入sockfd                if(fd == STDIN_FILENO && pfd[i].revents & kReadEvent)                {                    //從stdin接收資料寫入sendbuf                    if(buffer_read(&sendbuf, fd) == 0)                    {                        fprintf(stderr, "exit.\n");                        exit(EXIT_SUCCESS);                    }                 }                if(fd == STDOUT_FILENO && pfd[i].revents & kWriteEvent)                    buffer_write(&recvbuf, fd); //將recvbuf中的資料輸出至stdout            }        }    }}

從以上的代碼可以看出,大部分操作被封裝進了buffer的實現中。

 

測試伺服器,我暫時使用muduo庫編寫一個,代碼如下:

#include <muduo/net/TcpServer.h>#include <muduo/net/InetAddress.h>#include <muduo/net/TcpConnection.h>#include <muduo/base/Timestamp.h>#include <muduo/net/EventLoop.h>#include <muduo/base/Logging.h>using namespace muduo;using namespace muduo::net;void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp t){    string s(buf->retrieveAllAsString());    LOG_INFO << "recv msg : " << s.size() << " at: " << t.toFormattedString();    conn->send(s);}int main(int argc, char const *argv[]){    EventLoop loop;    InetAddress addr("192.168.44.136", 9981);    TcpServer server(&loop, addr, "EchoServer");    server.setMessageCallback(&onMessage);    server.start();    loop.loop();    return 0;}

讀者如果使用上述的代碼需要安裝muduo網路程式庫。

採用以下命令編譯:

g++ server.cpp  -lmuduo_net -lmuduo_base -lpthread -o server

 

下文用poll實現非阻塞的伺服器端。

Linux非阻塞IO(五)使用poll實現非阻塞的回射伺服器用戶端

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.