Hi experts,
Can you give some advice on my epoll code?
Is it correct or what?
Thank you.
$ pwd
/home/ljh/tmp/myapp/server
$ ls
main.out Makefile server.c server.d server.o
$
$ cat server.c
// server.c
//
16288...@qq.com
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <stdlib.h>
#define PORTNO "12345"
#define BACKLOG 5
#define MAXEVENTS 10
int setnonblocking(int fd)
{
int flags;
flags = fcntl(fd, F_GETFL, 0);
if (flags == -1){
perror ("fcntl");
return -1;
}
flags |= O_NONBLOCK;
flags = fcntl(fd, F_SETFL, flags);
if (flags == -1){
perror ("fcntl");
return -1;
}
return 0;
}
int main(void)
{
struct addrinfo hints, *result, *rp;
struct sockaddr addr;
socklen_t addrlen;
int sfd, ifd;
int optval;
int rt, errsv = 0;
char host[NI_MAXHOST], service[NI_MAXSERV];
char buf[128] = {'\0'};
struct epoll_event ev, *evp;
int efd, iefd, nefd;
char hostnm[20] = {'\0'};
time_t tm;
if (gethostname(hostnm, sizeof hostnm - 1) == -1){
perror("gethostname");
return -1;
}
memset(&hints, 0, sizeof hints);
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
rt = getaddrinfo(NULL, PORTNO, &hints, &result);
errsv = errno;
if (rt){
printf("%s: %s\n", "getaddrinfo gai_strerror",
gai_strerror(rt));
if (errsv)
perror("getaddrinfo");
return rt;
}
optval = 1;
for (rp = result; rp; rp = rp->ai_next){
ifd = socket(rp->ai_family, rp->ai_socktype, rp-
>ai_protocol);
if (ifd == -1)
continue;
if (setsockopt(ifd, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof optval) == -1){
perror("setsockopt");
return -1;
}
if (!bind(ifd, rp->ai_addr, rp->ai_addrlen))
break;
close(ifd);
}
if (!rp){
printf("Could not bind socket to any address\n");
return !rp;
}
if (listen(ifd, BACKLOG) == -1){
perror("listen");
return -1;
}
freeaddrinfo(result);
efd = epoll_create1(0);
if (efd == -1){
perror("epoll_create");
return -1;
}
ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
ev.data.fd = ifd;
if (epoll_ctl(efd, EPOLL_CTL_ADD, ifd, &ev) == -1){
perror("epoll_ctl");
return -1;
}
errsv = 0;
evp = calloc(MAXEVENTS, sizeof ev);
errsv = errno;
if (!evp){
printf("%s: %s\n", "calloc failed ", errsv ?
strerror(errsv) : "");
return !evp;
}
for (;;){
nefd = epoll_wait(efd, evp, MAXEVENTS, -1);
if (nefd == -1){
perror("epoll_wait");
return -1;
}
for (iefd = 0; iefd != nefd; iefd++){
if (evp[iefd].data.fd == ifd) {
addrlen = sizeof addr;
sfd = accept(ifd, &addr, &addrlen);
if (sfd == -1){
perror("accept");
return -1;
}
if (!getnameinfo(&addr, addrlen, host,
NI_MAXHOST, service, NI_MAXSERV, 0))
printf("Connection from %s
%s\n", host, service);
else
printf("Unknown %s %s\n",
host, service);
if (setnonblocking(sfd)){
printf("setnonblocking failed
\n");
return -1;
}
ev.events = EPOLLIN | EPOLLOUT |
EPOLLET;
ev.data.fd = sfd;
if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd,
&ev) == -1){
perror("epoll_ctl");
return -1;
}
} else {
if ((evp[iefd].events & EPOLLIN) ==
EPOLLIN){
memset(buf, 0, sizeof buf);
rt = recv(evp[iefd].data.fd,
buf, sizeof buf - 1, 0); //MSG_DONTWAIT
errsv = errno;
if (rt == -1){
printf("%s: %s\n",
"recv", strerror(errsv));
if (errsv ==
ECONNRESET || errsv == ENOTCONN){
close(sfd);
continue;
}
}
if (rt == 0){
printf("%s: %s\n",
"recv", "Peer has performed an orderly shutdown");
close(sfd);
continue;
}
if (strlen(buf))
printf("recv: client
time: [%d] %s", strlen(buf), buf);
sleep(1);
}
if ((evp[iefd].events & EPOLLOUT) ==
EPOLLOUT){
time(&tm);
snprintf(buf, sizeof buf, "%s:
%s", hostnm, ctime(&tm));
rt = send(evp[iefd].data.fd,
buf, strlen(buf), 0); //MSG_DONTWAIT
errsv = errno;
if (rt == -1){
printf("%s: %s\n",
"send", strerror(errsv));
if (errsv ==
ECONNRESET || errsv == ENOTCONN || errsv == EPIPE || errsv == EBADF){
close(evp[iefd].data.fd);
break;
}
}
}
if ((evp[iefd].events & EPOLLERR) ==
EPOLLERR ||
(evp[iefd].events & EPOLLHUP)
== EPOLLHUP ||
((evp[iefd].events & EPOLLIN)
!= EPOLLIN && (evp[iefd].events & EPOLLOUT) != EPOLLOUT))
{
close (evp[iefd].data.fd);
printf ("epoll error\n");
break;
}
}
}
}
// not reachable
free(evp);
close(ifd);
return 0;
}
$
$ pwd
/home/ljh/tmp/myapp/client
$ ls
client.c client.d client.o main.out Makefile
$
$ cat client.c
// client.c
//
16288...@qq.com
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#define PORTNO "12345"
int main(int argc, char *argv[])
{
struct addrinfo hints, *result, *rp;
int fd;
int rt;
int errsv = 0;
char buf[128] = {'\0'};
time_t tm;
char hostnm[20] = {'\0'};
if (argc < 2){
printf("%s <host>\n", argv[0]);
return -1;
}
if (gethostname(hostnm, sizeof hostnm - 1) == -1){
perror("gethostname");
return -1;
}
memset(&hints, 0, sizeof hints);
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
rt = getaddrinfo(argv[1], PORTNO, &hints, &result);
errsv = errno;
if (rt){
printf("%s: %s\n", "getaddrinfo gai_strerror",
gai_strerror(rt));
if (errsv)
perror("getaddrinfo");
return rt;
}
for (rp = result; rp; rp = rp->ai_next){
fd = socket(rp->ai_family, rp->ai_socktype, rp-
>ai_protocol);
if (fd == -1)
continue;
if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1)
break;
close(fd);
}
if (!rp){
printf("Could not connect socket to any address\n");
return !rp;
}
freeaddrinfo(result);
for (;;){
// send
time(&tm);
snprintf(buf, sizeof buf, "%s: %s", hostnm,
ctime(&tm));
rt = send(fd, buf, strlen(buf), MSG_DONTWAIT);
errsv = errno;
if (rt == -1){
printf("%s: %s\n", "send", strerror(errsv));
if (errsv == ECONNRESET || errsv == ENOTCONN
|| errsv == EPIPE){
close(fd);
break;
}
}
// recv
memset(buf, 0, sizeof buf);
rt = recv(fd, buf, sizeof buf - 1, MSG_DONTWAIT);
errsv = errno;
if (rt == -1){
printf("%s: %s\n", "recv", strerror(errsv));
if (errsv == ECONNRESET || errsv == ENOTCONN){
close(fd);
break;
}
}
if (rt == 0){
printf("%s: %s\n", "recv", "Peer has performed
an orderly shutdown");
close(fd);
break;
}
if (strlen(buf))
printf("recv: server time: [%d] %s",
strlen(buf), buf);
sleep(1);
}
close(fd);
return 0;
}
$
$ cat Makefile
# Visual Stupid Makefile
16288...@qq.com
# Layout: [include/] src/
# All .c and Makefile in src, .h can be in include. No other sub-
directories.
# Project related: CPPFLAGS
# .cpp, CXX, CXXFLAGS for C++
OUT = main.out
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(SRCS))
CC = gcc
CXX = g++
CFLAGS = -std=c99 -Wall -W
CXXFLAGS = -std=c++0x -Wall -W
CPPFLAGS = -I ../include
LDFLAGS =
CFLAGS += -g
#CFLAGS += -DNDEBUG
CFLAGS += -D_POSIX_SOURCE -D_BSD_SOURCE
LDFLAGS += -lpthread
$(OUT): $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@
include $(SRCS:.c=.d)
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
.PHONY : clean
clean:
rm *.d *.d.* $(OBJS) $(OUT)
$