TCP Echo Server (Revisited Again)
We now redo our TCP echo server from Section 6.8(See 8.4.8) using poll instead of select. In the previous version using select, we had to allocate a client array along with a descriptor set named rset (Figure 6.15(See 8.4.8)). With poll, we must allocate an array of pollfd structures to maintain the client information instead of allocating another array. We handle the fd member of this array the same way we handled the client array in Figure 6.15(See 8.4.8): a value of –1 means the entry is not in use; otherwise, it is the descriptor value. Recall from the previous section that any entry in the array of pollfd structures passed to poll with a negative value for the fd member is just ignored.
#include "unp.h"
#include <limits.h>
int main(int argc, char **)
{
int i,maxi, listenfd, connfd, sockfd;
int nready;
ssize_t n;
char buf[MAXLINE];
socklen_t clientlen;
struct pollfd client[OPEN_MAX];
struct sockaddr_in clientaddr, servaddr;
listenfd=Socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
client[0].fd=listenfd;
client[0].events=POLLRDNORM;
for(i=1;i<OPEN_MAX;i++)
client[i].fd=-1;
maxi=0;
for(;;)
{
nready=Poll(client,maxi+1, INFTIM);
if(client[0].revents& POLLRDNORM)
{
clientlen=sizeof(clientaddr);
connfd=Accept(listenfd, (SA *) &clientaddr, &clientlen);
for(i=1;i<OPEN_MAX;i++)
{
if(client[i].fd<0)
{
client[i].fd=connfd;
break;
}
}
if(i==OPEN_MAX)
err_quit("too many clients");
client[i].events=POLLRNDORM;
if(i>maxi)
maxi=i;
if(--nready<=0)
continue;
}
for(i=1;i<=maxi;i++)
{
if((sockfd=client[i].fd)<0)
continue;
if(client[i].revents&(POLLRNDORM))
if(errno==ECONNRESET)
{
Close(sockfd);
client[i].fd=-1;
}
else
err_sys("read error");
}
else if(n==0)
{
Close(sockfd);
client[i].fd=-1;
}
else
Writen(sockfd, buf, n);
if(--nready<=0)
break;
}
}
TCP server using poll