打印
[嵌入式linux]

高性能 tcp_echo

[复制链接]
1878|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sinanjj|  楼主 | 2011-10-14 22:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Echo, TCP, se, ST, TE
#include <sys/socket.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>

void become_daemon (void)
{
        switch (fork()) {        // fork off the parent process
                case -1: { printf ("error: fork()\n"); exit(0); }
                case 0: break;
                default: exit (0);
        }
        umask (0);        // change the file mode mask
        setsid();        // creates a new session
        chdir ("/");        // change the current working directory
        close (STDIN_FILENO); close (STDOUT_FILENO); close (STDERR_FILENO);        // close out the standard file descriptors
}

void tcp_keepalive(int tcp_fd)
{
//  keepalive probe packets: no data and ACK set tcp packets
        int keepAlive = 1;
        if (setsockopt (tcp_fd,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1) { syslog(LOG_INFO, "error: setsockopt() SO_KEEPALIVE\n"); exit (0); }
        int keepIdle = 1;        // The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes
        if (setsockopt (tcp_fd,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1) { syslog(LOG_INFO, "error: setsockopt() TCP_KEEPIDLE\n"); exit(0); }
        int keepInterval = 1;        // The time (in seconds) between individual keepalive probes
        if (setsockopt (tcp_fd,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1) { syslog(LOG_INFO, "error: setsockopt() TCP_KEEPINTVL\n"); exit(0); }
        int keepCount = 3;        // The maximum number of keepalive probes TCP should send before dropping the connection
        if (setsockopt (tcp_fd,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1) { syslog(LOG_INFO, "error: setsockopt() TCP_KEEPCNT\n"); exit(0); }
}

void close_clean(int fd)
{
        // clean
        close (fd);
        return;
}

void do_use_fd (int fd, unsigned char fin_flag)
{
#define BUF_SIZE 1500
        unsigned char buf[BUF_SIZE+1]; bzero (buf, BUF_SIZE+1);
        int len;
        len = read (fd, buf, BUF_SIZE);

        if (len == -1) {        // rst
                shutdown(fd, SHUT_RDWR); close_clean (fd);
                return;
        }
        if (len == 0) {        // fin
                shutdown(fd, SHUT_RDWR); close_clean (fd);
                return;
        }

        while (len > 0) {
                // rx data hander        begin
                if (sendto(fd, buf, len, MSG_DONTWAIT, NULL, 0) == -1) {
                        if((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                                shutdown(fd, SHUT_RDWR); close_clean (fd); return;
                        }
                        syslog(LOG_INFO,"error: sendto() %d\n", errno); exit (0);
                }
                // rx data hander        end

                len = -1;
                len = read (fd, buf, BUF_SIZE);
                if (len == -1) {
                        if((errno == EAGAIN) || (errno == EWOULDBLOCK)) {        // Non-blocking I/O has been selected using O_NONBLOCK and no data was immediately available for reading
                                break;
                        } else { syslog(LOG_INFO,"error: read() errno != EAGAIN\n"); exit (0); }
                } else if (len == 0) {
                        fin_flag = 1;
                }
        }

        if (fin_flag > 0) {        // fin
                shutdown(fd, SHUT_RDWR); close_clean (fd);
                return;
        }
        return;
}

int main ()
{
        become_daemon ();

        int listen_fd;
        if ((listen_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { syslog(LOG_INFO,"error: socket()\n"); exit (0); }
        struct sockaddr_in acceptAddress;
        acceptAddress.sin_family = PF_INET;
        acceptAddress.sin_addr.s_addr = htonl (INADDR_ANY);
#define LISTEN_PORT 2000
        acceptAddress.sin_port = htons (LISTEN_PORT);
        if (bind (listen_fd, (struct sockaddr *)&acceptAddress, sizeof(struct sockaddr)) != 0) { syslog(LOG_INFO,"error: bind()\n"); exit (0); }
        listen (listen_fd, 10000);
        tcp_keepalive(listen_fd);
        int flag = 1;
        if (setsockopt(listen_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) == -1) { syslog(LOG_INFO,"error: setsockopt(TCP_NODELAY)\n"); exit(0); }        // Disable the Nagle (TCP No Delay) algorithm

        signal(SIGPIPE, SIG_IGN);

        int epoll_fd;
        epoll_fd = epoll_create(1);
        struct epoll_event ev, *events;
#define MAX_EVENTS 100
        events = (struct epoll_event *) malloc(MAX_EVENTS*sizeof(struct epoll_event));
        bzero (events, MAX_EVENTS*sizeof(struct epoll_event));

/*
syn --> EPOLLIN
data --> EPOLLIN
fin --> EPOLLIN|EPOLLRDHUP read() return len(rx_buf)
rst --> EPOLLIN read() return -1
*/
        ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
        ev.data.fd = listen_fd;
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev) != 0) { syslog(LOG_INFO,"error: epoll_ctl() listen_fd\n"); exit(0); }

        for(;;) {
                int n_fds;
                n_fds = epoll_wait (epoll_fd, events, MAX_EVENTS, -1);
                int i;
                for(i=0; i<n_fds; i++) {
                        if (events[i].events & (EPOLLERR | EPOLLHUP)) {        // error
                                if (events[i].data.fd == listen_fd) { syslog(LOG_INFO,"error: listen_fd\n"); exit(0); }
                                close_clean (events[i].data.fd);        // close(fd) cause fd to be removed from all epoll sets automatically
                        } else if (events[i].events & EPOLLRDHUP) {        // fin
                                do_use_fd(events[i].data.fd, 1);
                        } else if (events[i].events & EPOLLIN) {
                                if (events[i].data.fd == listen_fd) {        // syn
                                        struct sockaddr_in clientAddr;
                                        bzero(&clientAddr, sizeof(struct sockaddr_in));
                                        int client_fd, len;
                                        len = sizeof (struct sockaddr_in);
                                        client_fd = accept (listen_fd, (struct sockaddr *)&clientAddr, (socklen_t *)&len);        // accept() creates a new connected socket file descriptor
                                        if(client_fd < 0) { continue; }
                                        if (fcntl(client_fd, F_SETFL, O_NONBLOCK) != 0) { syslog(LOG_INFO,"error: fcntl(). exit\n"); exit (0); }        // set client_fd nonblocking
                                        ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
                                        ev.data.fd = client_fd;
                                        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) { syslog(LOG_INFO,"error: epoll_ctl\n"); exit(0); }
                                } else { do_use_fd(events[i].data.fd, 0); }        // data | rst
                        } else {  syslog(LOG_INFO,"unknown event\n"); exit(0); }
                }
        }

        close (listen_fd);
        close (epoll_fd);
        free (events);
        return 0;
}

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:In God We Trust 独立的个人,体赖科学技术工具提供针对个人的产品与服务,是通向幸福的唯一道路 工程师,设计师等可以个人创业的群体,将逐步瓦解官僚体制公司,成为中国中产。(重复劳动,工厂等,将逐步机械化) seacer.co

456

主题

6300

帖子

25

粉丝