Skip to content

Instantly share code, notes, and snippets.

@oxnz
Created May 3, 2014 16:58
Show Gist options
  • Save oxnz/95d3ee80b20af60308dc to your computer and use it in GitHub Desktop.
Save oxnz/95d3ee80b20af60308dc to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
void evecho(const char *prefix, const struct epoll_event *events, int idx,
const char *suffix) {
if (NULL != prefix) {
printf("%s:", prefix);
}
printf("events[%d].data.fd(%d)", idx, events[idx].data.fd);
if (NULL != suffix) {
printf(": %s", suffix);
}
if (NULL == suffix || '\n' != suffix[strlen(suffix)-1]) {
putchar('\n');
}
}
void errpro(int condition, const char *errmsg) {
if (condition) {
perror(errmsg);
exit(EXIT_FAILURE);
}
}
int reuseaddr(int fd) {
int opval = 1;
errpro(-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opval,
sizeof(opval)),
"setsockopt");
return 0;
}
int disblock(int fd) {
int flags = fcntl(fd, F_GETFL);
errpro(-1 == flags, "fcntl");
errpro(-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK), "fcntl");
return 0;
}
#define PORT 8888U
#define BACKLOG 16U
#define BUFLEN 64U
#define MAXCON 128U
int main() {
struct sockaddr_in cli_addr, ser_addr;
socklen_t addrlen = sizeof(sockaddr_in);
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
errpro(-1 == listenfd, "socket");
reuseaddr(listenfd);
disblock(listenfd); //把socket设置为非阻塞方式
struct epoll_event ev, events[MAXCON];
ev.data.fd = listenfd;
ev.events = EPOLLIN|EPOLLET;
int epfd = epoll_create(true);
errpro(-1 == epfd, "epoll_create");
errpro(-1 == epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev), "epoll_ctl");
memset(&ser_addr, 0, sizeof(sockaddr_in));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ser_addr.sin_port = htons(PORT);
errpro(-1 == bind(listenfd, (struct sockaddr *)&ser_addr,
addrlen), "bind");
errpro(-1 == listen(listenfd, BACKLOG), "listen");
static int loop = 0;
for (;;) {
printf("loop %d\n", ++loop);
int timeout = 10000; // 10 seconds
int nfds = epoll_wait(epfd, events, MAXCON, timeout);
errpro(-1 == nfds, "epoll_wait");
if (0 == nfds) {
printf("timeout\n");
continue;
}
for (int i = 0; i < nfds; ++i) {
if (events[i].data.fd == listenfd) { // new connection(s)
evecho(NULL, events, i, "ready for connection");
while (true) {
int fd = accept(listenfd, (sockaddr *)&cli_addr, &addrlen);
errpro(-1 == fd && EWOULDBLOCK != errno, "accept");
if (EWOULDBLOCK == errno) {
errno = 0; // already accept all the incoming conn(s)
break;
}
printf("accepted: %s, fd: %d\n", inet_ntoa(cli_addr.sin_addr), fd);
disblock(fd);
ev.data.fd = fd;
ev.events = EPOLLIN|EPOLLET;
errpro(-1 == epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev),
"epoll_ctl");
}
} // data ready from established connections
else if (EPOLLIN & events[i].events) {
evecho(NULL, events, i, "ready for read");
if (-1 == events[i].data.fd) {
evecho("closed fd", events, i, NULL);
continue;
}
char buf[BUFLEN];
int n = read(events[i].data.fd, buf, BUFLEN-1);
if ((-1 == n && ECONNRESET == errno) || 0 == n) {
evecho("close", events, i,
-1 == n ? "cause ECONNRESET":"cause read 0 byte");
close(events[i].data.fd);
events[i].data.fd = -1;
}
errpro(-1 == n, "read");
buf[n] = '\0';
evecho("message from", events, i, buf);
ev.data.fd = events[i].data.fd;
ev.events = EPOLLOUT|EPOLLET;
errpro(-1 == epoll_ctl(epfd, EPOLL_CTL_MOD, events[i].data.fd,
&ev), "epoll_ctl");
} // fd ready for write
else if (EPOLLOUT & events[i].events) {
evecho(NULL, events, i, "ready for write");
char msg[] = "->reply from server\n";
errpro(-1 == write(events[i].data.fd, msg, strlen(msg)),
"write");
ev.data.fd = events[i].data.fd;
ev.events = EPOLLIN|EPOLLET;
errpro(-1 == epoll_ctl(epfd, EPOLL_CTL_MOD, events[i].data.fd,
&ev), "epoll_ctl");
} else { // non-sense
errpro(EXIT_FAILURE, "unknow error");
}
}
}
close(epfd);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment