[嵌入式linux] 高性能 tcp_echo

[复制链接]
2547|0
 楼主| sinanjj 发表于 2011-10-14 22:52 | 显示全部楼层 |阅读模式
Echo, TCP, se, ST, TE
  1. #include <sys/socket.h>
  2. #include <sys/epoll.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <arpa/inet.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <netinet/in.h>
  9. #include <netinet/tcp.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. #include <errno.h>
  14. #include <signal.h>
  15. #include <syslog.h>

  16. void become_daemon (void)
  17. {
  18.         switch (fork()) {        // fork off the parent process
  19.                 case -1: { printf ("error: fork()\n"); exit(0); }
  20.                 case 0: break;
  21.                 default: exit (0);
  22.         }
  23.         umask (0);        // change the file mode mask
  24.         setsid();        // creates a new session
  25.         chdir ("/");        // change the current working directory
  26.         close (STDIN_FILENO); close (STDOUT_FILENO); close (STDERR_FILENO);        // close out the standard file descriptors
  27. }

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

  40. void close_clean(int fd)
  41. {
  42.         // clean
  43.         close (fd);
  44.         return;
  45. }

  46. void do_use_fd (int fd, unsigned char fin_flag)
  47. {
  48. #define BUF_SIZE 1500
  49.         unsigned char buf[BUF_SIZE+1]; bzero (buf, BUF_SIZE+1);
  50.         int len;
  51.         len = read (fd, buf, BUF_SIZE);

  52.         if (len == -1) {        // rst
  53.                 shutdown(fd, SHUT_RDWR); close_clean (fd);
  54.                 return;
  55.         }
  56.         if (len == 0) {        // fin
  57.                 shutdown(fd, SHUT_RDWR); close_clean (fd);
  58.                 return;
  59.         }

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

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

  79.         if (fin_flag > 0) {        // fin
  80.                 shutdown(fd, SHUT_RDWR); close_clean (fd);
  81.                 return;
  82.         }
  83.         return;
  84. }

  85. int main ()
  86. {
  87.         become_daemon ();

  88.         int listen_fd;
  89.         if ((listen_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { syslog(LOG_INFO,"error: socket()\n"); exit (0); }
  90.         struct sockaddr_in acceptAddress;
  91.         acceptAddress.sin_family = PF_INET;
  92.         acceptAddress.sin_addr.s_addr = htonl (INADDR_ANY);
  93. #define LISTEN_PORT 2000
  94.         acceptAddress.sin_port = htons (LISTEN_PORT);
  95.         if (bind (listen_fd, (struct sockaddr *)&acceptAddress, sizeof(struct sockaddr)) != 0) { syslog(LOG_INFO,"error: bind()\n"); exit (0); }
  96.         listen (listen_fd, 10000);
  97.         tcp_keepalive(listen_fd);
  98.         int flag = 1;
  99.         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

  100.         signal(SIGPIPE, SIG_IGN);

  101.         int epoll_fd;
  102.         epoll_fd = epoll_create(1);
  103.         struct epoll_event ev, *events;
  104. #define MAX_EVENTS 100
  105.         events = (struct epoll_event *) malloc(MAX_EVENTS*sizeof(struct epoll_event));
  106.         bzero (events, MAX_EVENTS*sizeof(struct epoll_event));

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

  116.         for(;;) {
  117.                 int n_fds;
  118.                 n_fds = epoll_wait (epoll_fd, events, MAX_EVENTS, -1);
  119.                 int i;
  120.                 for(i=0; i<n_fds; i++) {
  121.                         if (events[i].events & (EPOLLERR | EPOLLHUP)) {        // error
  122.                                 if (events[i].data.fd == listen_fd) { syslog(LOG_INFO,"error: listen_fd\n"); exit(0); }
  123.                                 close_clean (events[i].data.fd);        // close(fd) cause fd to be removed from all epoll sets automatically
  124.                         } else if (events[i].events & EPOLLRDHUP) {        // fin
  125.                                 do_use_fd(events[i].data.fd, 1);
  126.                         } else if (events[i].events & EPOLLIN) {
  127.                                 if (events[i].data.fd == listen_fd) {        // syn
  128.                                         struct sockaddr_in clientAddr;
  129.                                         bzero(&clientAddr, sizeof(struct sockaddr_in));
  130.                                         int client_fd, len;
  131.                                         len = sizeof (struct sockaddr_in);
  132.                                         client_fd = accept (listen_fd, (struct sockaddr *)&clientAddr, (socklen_t *)&len);        // accept() creates a new connected socket file descriptor
  133.                                         if(client_fd < 0) { continue; }
  134.                                         if (fcntl(client_fd, F_SETFL, O_NONBLOCK) != 0) { syslog(LOG_INFO,"error: fcntl(). exit\n"); exit (0); }        // set client_fd nonblocking
  135.                                         ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
  136.                                         ev.data.fd = client_fd;
  137.                                         if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) { syslog(LOG_INFO,"error: epoll_ctl\n"); exit(0); }
  138.                                 } else { do_use_fd(events[i].data.fd, 0); }        // data | rst
  139.                         } else {  syslog(LOG_INFO,"unknown event\n"); exit(0); }
  140.                 }
  141.         }

  142.         close (listen_fd);
  143.         close (epoll_fd);
  144.         free (events);
  145.         return 0;
  146. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

456

主题

6299

帖子

25

粉丝
快速回复 在线客服 返回列表 返回顶部