Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

epoll socket example code review

744 views
Skip to first unread message

lovecreatesbeauty

unread,
Apr 19, 2012, 10:24:43 PM4/19/12
to
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)

$
0 new messages