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

please help review epoll networking code

29 views
Skip to first unread message

lovecreatesbeauty

unread,
Aug 30, 2012, 12:13:34 PM8/30/12
to
1. How does the code handle EPOLLIN, EPOLLOUT, EPOLLERR this way?

for (iefd = 0; iefd != nefd; iefd++){
if (evp[iefd].data.fd == sfd) {
...
} else {

if ((evp[iefd].events & EPOLLIN) == EPOLLIN){
...
}

if ((evp[iefd].events & EPOLLOUT) == EPOLLOUT){
...
}

if ((evp[iefd].events & EPOLLERR) == EPOLLERR ||
(evp[iefd].events & EPOLLHUP) == EPOLLHUP ||
((evp[iefd].events & EPOLLIN) != EPOLLIN && (evp[iefd].events & EPOLLOUT) != EPOLLOUT))
{
...
}

2. Do I need to use epoll functions on client side which calls connect()?

I see some select() example which applies select functions on both server and client sides.


Thank you for your time!


////////////////////////////////////////////////////////////////////////////////
// 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){
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) == -1){
perror("setsockopt");
return -1;
}
if (!bind(sfd, rp->ai_addr, rp->ai_addrlen))
break;
close(sfd);
}
if (!rp){
printf("Could not bind socket to any address\n");
return !rp;
}

if (listen(sfd, 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 = sfd;
if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &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 == sfd) {
addrlen = sizeof addr;
ifd = accept(sfd, &addr, &addrlen);
if (ifd == -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(ifd)){
printf("setnonblocking failed\n");
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;
}
} else {
if ((evp[iefd].events & EPOLLIN) == EPOLLIN){
memset(buf, 0, sizeof buf);

//partial read or recv? not handled
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(evp[iefd].data.fd);
continue;
}
}
if (rt == 0){
printf("%s: %s\n", "recv", "Peer has performed an orderly shutdown");
close(evp[iefd].data.fd);
continue;
}
if (strlen(buf))
printf("recv: client time: %d %s", strlen(buf), buf);
}

if ((evp[iefd].events & EPOLLOUT) == EPOLLOUT){
time(&tm);
snprintf(buf, sizeof buf, "%s %s", hostnm, ctime(&tm));

//partial write or send? not handled
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);
continue;
}
}
}

if ((evp[iefd].events & EPOLLERR) == EPOLLERR ||
(evp[iefd].events & EPOLLHUP) == EPOLLHUP ||
((evp[iefd].events & EPOLLIN) != EPOLLIN && (evp[iefd].events & EPOLLOUT) != EPOLLOUT))
{
printf ("Unknown event: %d\n", evp[iefd].events);
close (evp[iefd].data.fd);
continue;
}
}
}
}

// not reachable
free(evp);
close(sfd);
return 0;
}


////////////////////////////////////////////////////////////////////////////////
// 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 (;;){

sleep(1); //Block revc / send used - no MSG_DONTWAIT
//temporary for demo only
//Normal code does not require this sleep.

// send
time(&tm);
snprintf(buf, sizeof buf, "%s %s", hostnm, ctime(&tm));
rt = send(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){
close(fd);
break;
}
}

// recv
memset(buf, 0, sizeof buf);
rt = recv(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(fd);
break;
}
}
if (rt == 0){
close(fd);
printf("%s: %s\n", "recv", "Peer has performed an orderly shutdown");
break;
}
if (strlen(buf))
printf("recv: server time: %d %s", strlen(buf), buf);
}
close(fd);
return 0;
}

Jorgen Grahn

unread,
Aug 30, 2012, 4:03:43 PM8/30/12
to
On Thu, 2012-08-30, lovecreatesbeauty wrote:
...
> 2. Do I need to use epoll functions on client side which calls connect()?
>
> I see some select() example which applies select
> functions on both server and client sides.

Select and epoll (which is Linux-specific, by the way) are used for
the same kinds of things.

Look at all your system calls which may block for a long time. Ask
yourself for each one "is it ok if I block here for a minute?". If
the answer is "yes" you don't need select/epoll.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
0 new messages