Linux poll服务端
源代码:pollServer.cpp
/*******************************************************************************
* pollServer.cpp
*
* Create on 2018-10-6
* Author: yanxinchun
*
* g++ -o pollServer pollServer.cpp
*******************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/poll.h>
#define POLL_MAX_CN (1024)
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
typedef struct _packet_st {
int len;
char buf[1024];
} PACKET_st;
ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf;
while(nleft > 0){
if(nread = read(fd, bufp, nleft) < 0) {
if(errno == EINTR) {
continue;
}
return -1;
}else if(nread == 0) {
return count - nleft;
}
bufp += nread;
nleft -= nread;
}
return count;
}
ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf;
while(nleft > 0) {
if(nwritten = write(fd, bufp, nleft) < 0) {
if(errno == EINTR) {
continue;
}
return -1;
}else if(nwritten == 0) {
continue;
}
bufp += nwritten;
nleft -= nwritten;
}
return count;
}
void handle_sigpipe(int sig)
{
printf("[sigpipe] recv a sig=%d\n", sig);
}
void handle_sigchld(int sig)
{
while(waitpid(-1, NULL, WNOHANG) > 0) ;
}
int main()
{
//往一个已经关闭的socket写入数据会触发SIGPIPE
signal(SIGPIPE, handle_sigpipe);
/* 在一个进程停止或终止时,将SIGPIPE信号发送给其父进程,按系统默认将忽略此信号,
如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。*/
signal(SIGCHLD, handle_sigchld);
int listenfd = socket(PF_INET, SOCK_STREAM, 0);
if(listenfd < 0) {
ERR_EXIT("socket fail!");
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8914);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int on = 1;
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
ERR_EXIT("setsockopt fail!");
}
if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
ERR_EXIT("bind fail!");
}
if(listen(listenfd, SOMAXCONN) < 0) {
ERR_EXIT("listen fail!");
}
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int conn;
PACKET_st recvbuf;
int i;
int maxi = 0;
struct pollfd client[POLL_MAX_CN];
for(i = 0; i < POLL_MAX_CN; ++i) {
client[i].fd = -1;
}
int nready;
client[0].fd = listenfd;
client[0].events = POLLIN;
while(1){
nready = poll(client, maxi + 1, -1);
if(nready == -1) {
if(errno == EINTR) {
continue;
}
ERR_EXIT("poll");
}
if(nready == 0) {
//printf("nready=%d, continue\n", nready);
continue;
}
if(client[0].revents & POLLIN) {
printf("listen...\n");
peerlen = sizeof(peeraddr);
conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);
if(conn == -1) {
ERR_EXIT("accept fail!");
}
for(i = 0; i < POLL_MAX_CN; ++i) {
if(client[i].fd < 0) {
client[i].fd = conn;
if(i > maxi) {
maxi = i;
}
break;
}
}
if(i == POLL_MAX_CN) {
fprintf(stderr, "too many clients\n");
exit(EXIT_FAILURE);
}
printf("accept ip=%s, port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
//printf("maxi=%d, i=%d\n", maxi, i);
client[i].events = POLLIN;
if(--nready <= 0) {
//printf("nready=%d, continue\n", nready);
continue;
}
}
for(i = 1; i <= maxi; ++i) {
conn = client[i].fd;
if(conn == -1) {
continue;
}
if(client[i].revents & POLLIN) {
int n;
int ret;
memset(&recvbuf, 0, sizeof(recvbuf));
ret = read(conn, &recvbuf.len, 4);
if(ret == -1) {
ERR_EXIT("ser read fail 11!");
}else if(ret < 4) {
printf("client close, ret = %d\n", ret);
client[i].fd = -1;
shutdown(conn, SHUT_WR);
} else {
n = ntohl(recvbuf.len);
ret = read(conn, &recvbuf.buf, n);
if(ret == -1) {
ERR_EXIT("ser read fail 22!");
} else if(ret < n) {
printf("client close 22, ret = %d\n", ret);
client[i].fd = -1;
shutdown(conn, SHUT_WR);
}
printf("recv: len=%d, ctx=%s", ntohl(recvbuf.len), recvbuf.buf);
//fputs(recvbuf.buf, stdout);
printf("reply: len=%d, ctx=%s\n", ntohl(recvbuf.len), recvbuf.buf);
write(conn, &recvbuf, 4 + n);
}
if(--nready <= 0) {
break;
}
}
}
}
close(listenfd);
return 0;
}
编译运行:
[root@QIANZI-BASE keke]# g++ -o pollServer pollServer.cpp