Linux epoll客户端
源代码:epollClient.cpp
/*******************************************************
* epollClient.cpp
*
* Create on 2018-10-6
* Author: yanxinchun
*
* g++ -o epollClient epollClient.cpp
*******************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <vector>
#include <algorithm>
#include <assert.h>
#define POLL_MAX_CN (1024)
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
typedef std::vector<struct epoll_event> EventList;
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;
}
int getlocalip(char *ip) {
char host[100] = {0};
if(gethostname(host, sizeof(host)) < 0) {
return -1;
}
struct hostent* hp;
if((hp = gethostbyname(host)) == NULL) {
return -1;
}
strcpy(ip, inet_ntoa(*(struct in_addr*)hp->h_addr_list[0]));
//int i = 0;
//while(hp->h_addr_list[i] != NULL) {
// printf("%s\n", inet_ntoa(*(struct in_addr*)hp->h_addr_list[i]));
// ++i;
//}
return 0;
}
/**
* * * activate_nonblock - 设置I/O为非阻塞模式
* * * @fd: 文件描述符
* * */
void activate_nonblock(int fd)
{
int ret;
int flags = fcntl(fd, F_GETFL);
if(flags == -1) {
ERR_EXIT("fcntl fail!");
}
flags |= O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if(ret == -1) {
ERR_EXIT("fcntl fail!");
}
}
/**
* * * deactivate_nonblock - 设置I/O为阻塞模式
* * * @fd: 文件描述符
* * */
void deactivate_nonblock(int fd)
{
int ret;
int flags = fcntl(fd, F_GETFL);
if(flags == -1) {
ERR_EXIT("fcntl fail!");
}
flags &= ~O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if(ret == -1) {
ERR_EXIT("fcntl fail!");
}
}
void handle_sigpipe(int sig)
{
printf("[sigpipe] recv a sig=%d\n", sig);
}
int main()
{
//往一个已经关闭的socket写入数据会触发SIGPIPE
signal(SIGPIPE, handle_sigpipe);
int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock < 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 = inet_addr("127.0.0.1");
// connect
if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
ERR_EXIT("connect fail!");
}
/*
printf("client connect success\n");
char ip[32] = {0};
getlocalip(ip);
printf("local ip: %s\n", ip);
*/
struct sockaddr_in localaddr;
socklen_t addrlen = sizeof(localaddr);
if(getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) < 0){
ERR_EXIT("getsockname fail!");
}
printf("local ip=%s, port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));
PACKET_st recvbuf;
PACKET_st sendbuf;
memset(&recvbuf, 0, sizeof(recvbuf));
memset(&sendbuf, 0, sizeof(sendbuf));
std::vector<int> clients;
int epollfd = epoll_create1(EPOLL_CLOEXEC); // 用于设置改描述符的close-on-exec(FD_CLOEXEC)标志
struct epoll_event event;
int fd_stdin = fileno(stdin);
event.data.fd = fd_stdin;
event.events = EPOLLIN | EPOLLET;
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd_stdin, &event);
event.data.fd = sock;
event.events = EPOLLIN | EPOLLET;
epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &event);
EventList events(4);
int i;
int nready = 0;
while(1){
nready = epoll_wait(epollfd, &*events.begin(), static_cast<int>(events.size()), -1);
if(nready == -1) {
if(errno == EINTR) {
continue;
}
ERR_EXIT("epoll_wait fail!");
}
if(nready == 0) {
continue;
}
if((size_t)nready == events.size()) {
events.resize(events.size() * 2);
}
for(i = 0; i < nready; ++i) {
if(events[i].data.fd == fd_stdin) {
//printf("stdin ......\n");
if(fgets(sendbuf.buf, sizeof(sendbuf.buf), stdin) == NULL){
printf("stdin is null ...\n");
shutdown(sock, SHUT_WR);
event = events[i];
epoll_ctl(epollfd, EPOLL_CTL_DEL, fd_stdin, &event);
} else {
int len = strlen(sendbuf.buf);
sendbuf.len = htonl(len);
write(sock, &sendbuf, 4 + len);
memset(&sendbuf, 0, sizeof(sendbuf));
}
} else if(events[i].data.fd == sock) {
if(sock < 0){
continue;
}
//printf("sock in ......\n");
int ret = read(sock, &recvbuf.len, 4);
if(ret == -1) {
ERR_EXIT("cli read fail!");
} else if(ret < 4) {
printf("server close 1.\n");
shutdown(sock, SHUT_WR);
event = events[i];
epoll_ctl(epollfd, EPOLL_CTL_DEL, sock, &event);
return 0;
}
int n = ntohl(recvbuf.len);
ret = read(sock, &recvbuf.buf, n);
if(ret == -1) {
ERR_EXIT("cli read fail!");
} else if(ret < n) {
printf("server close 2\n");
shutdown(sock, SHUT_WR);
event = events[i];
epoll_ctl(epollfd, EPOLL_CTL_DEL, sock, &event);
return 0;
}
printf("recv: len=%d, ctx=%s", ntohl(recvbuf.len), recvbuf.buf);
//fputs(recvbuf.buf, stdout);
memset(&recvbuf, 0, sizeof(recvbuf));
}
}
}
return 0;
}
编译运行:
[root@QIANZI-BASE keke]# g++ -o epollClient epollClient.cpp