In the previous sections we discussed the basic concepts of nonblocking IO, the design of buffer and the implementation of non-blocking connect, which we now use to complete the client's writing.
As we have suggested in http://www.cnblogs.com/inevermore/p/4049165.html, the client needs to monitor stdin, stdout, and SOCKFD.
It's important to note that
Only the buffer can be written, only to listen to SOCKFD and stdin read events.
In the past in blocking IO, we always listen to SOCKFD read events, because whenever sockfd readable, we go to call the user's callback function to handle the read event, in the callback function requires the user to manually read buffer data. In other words, receiving data is the responsibility of the user, and the poll model only needs to remind the user to receive it.
In non-blocking IO, because poll uses a horizontal trigger, if the buffer is full and each read equals an invalid operation, the data is always stacked in the kernel, and poll is constantly triggered. this is in some way equal to polling. So we only listen for SOCKFD read events when the buffer is available.
Only when the buffer is readable can we listen to the write events of SOCKFD and stdout. Since there is no data to write, listening for write events has no practical meaning except for the constant triggering of poll.
It is necessary to reload the events array of poll before each execution of the poll.
The complete code is as follows:
#include"sysutil.h"#include"Buffer.h"intMainintargcChar Const*argv[]) { //Create a client socket intSOCKFD = Tcp_client (8934); //call the non-blocking connect function intret = Nonblocking_connect (SOCKFD,"192.168.44.136",9981, the); if(ret = =-1) {fprintf (stderr,"Timeout. \ n"); Exit (Exit_failure); } //set three fd to Non-blockingActivate_nonblock (SOCKFD); Activate_nonblock (Stdin_fileno); Activate_nonblock (Stdout_fileno); buffer_t Recvbuf; //SOCKFD, stdout, Bufferbuffer_t SendBuf;//stdin, SOCKFD, Buffer//Initializing buffersBuffer_init (&recvbuf); Buffer_init (&sendbuf); structPOLLFD pfd[Ten]; while(1) { //Initialize intIX; for(ix =0; IX! =3; ++ix) {PFD[IX].FD= -1; Pfd[ix].events=0; } //Reload Events Array 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; } //listen for FD array intNready = Poll (PFD,3, the); if(Nready = =-1) Err_exit ("Poll"); Else if(Nready = =0) {printf ("timeout\n"); Continue; } Else { inti; for(i =0; I <3; ++i) {intFD =PFD[I].FD; if(FD = = sockfd && pfd[i].revents &kreadevent) { //receive data from SOCKFD to 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);//writes data from SendBuf to SOCKFD if(FD = = Stdin_fileno && pfd[i].revents &kreadevent) { //receive data from stdin write 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);//output data from the RECVBUF to stdout } } }}
As can be seen from the above code, most operations are encapsulated in the implementation of buffer.
To test the server, I use the Muduo library for the time being to write a code as follows:
#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 namespaceMuduo;using namespacemuduo::net;voidOnMessage (ConstTcpconnectionptr &conn, Buffer *buf, Timestamp t) { stringS (buf->retrieveallasstring ()); Log_info<<"recv msg:"<< s.size () <<"At :"<<t.toformattedstring (); Conn-send (s);}intMainintargcChar 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;}
Readers who use the above code need to install the Muduo network library.
compile with the following command:
g++ server.cpp -lmuduo_net-lmuduo_base-lpthread-o Server
The following uses poll to implement a non-blocking server side.
Linux non-blocking IO (v) Implementation of non-blocking loopback server client using poll