`
haoningabc
  • 浏览: 1483036 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

epoll的helloworld

阅读更多
转https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/
说明:介绍来自http://baike.baidu.com/view/1385104.htm
epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它不会复用文件描述符集合来传递结果而迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的电平触发(Level Triggered)外,还提供了边沿触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

官方的运行不了,有错误,看我这个
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>

#define MAXEVENTS 64

static int
make_socket_non_blocking (int sfd)
{
  int flags, s;

  flags = fcntl (sfd, F_GETFL, 0);
  if (flags == -1)
    {
      perror ("fcntl");
      return -1;
    }

  flags |= O_NONBLOCK;
  s = fcntl (sfd, F_SETFL, flags);
  if (s == -1)
    {
      perror ("fcntl");
      return -1;
    }

  return 0;
}

static int
create_and_bind (char *port)
{
  struct addrinfo hints;
  struct addrinfo *result, *rp;
  int s, sfd;

  memset (&hints, 0, sizeof (struct addrinfo));
  hints.ai_family = AF_UNSPEC;     /* Return IPv4 and IPv6 choices */
  hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
  hints.ai_flags = AI_PASSIVE;     /* All interfaces */

  s = getaddrinfo (NULL, port, &hints, &result);
  if (s != 0)
    {
      fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));
      return -1;
    }

  for (rp = result; rp != NULL; rp = rp->ai_next)
    {
      sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
      if (sfd == -1)
        continue;

      s = bind (sfd, rp->ai_addr, rp->ai_addrlen);
      if (s == 0)
        {
          /* We managed to bind successfully! */
          break;
        }

      close (sfd);
    }

  if (rp == NULL)
    {
      fprintf (stderr, "Could not bind\n");
      return -1;
    }

  freeaddrinfo (result);

  return sfd;
}

int
main (int argc, char *argv[])
{
  int sfd, s;
  int efd;
  struct epoll_event event;
  struct epoll_event *events;

  if (argc != 2)
    {
      fprintf (stderr, "Usage: %s [port]\n", argv[0]);
      exit (EXIT_FAILURE);
    }

  sfd = create_and_bind (argv[1]);
  if (sfd == -1)
    abort ();

  s = make_socket_non_blocking (sfd);
  if (s == -1)
    abort ();

  s = listen (sfd, SOMAXCONN);
  if (s == -1)
    {
      perror ("listen");
      abort ();
    }

  efd = epoll_create (0);//error in original page
  if (efd == -1)
    {
      perror ("epoll_create");
      abort ();
    }

  event.data.fd = sfd;
  event.events = EPOLLIN | EPOLLET;
  s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event);
  if (s == -1)
    {
      perror ("epoll_ctl");
      abort ();
    }

  /* Buffer where events are returned */
  events = calloc (MAXEVENTS, sizeof event);

  /* The event loop */
  while (1)
    {
      int n, i;

      n = epoll_wait (efd, events, MAXEVENTS, -1);
      for (i = 0; i < n; i++)
	{
	  if ((events[i].events & EPOLLERR) ||
              (events[i].events & EPOLLHUP) ||
              (!(events[i].events & EPOLLIN)))
	    {
              /* An error has occured on this fd, or the socket is not
                 ready for reading (why were we notified then?) */
	      fprintf (stderr, "epoll error\n");
	      close (events[i].data.fd);
	      continue;
	    }

	  else if (sfd == events[i].data.fd)
	    {
              /* We have a notification on the listening socket, which
                 means one or more incoming connections. */
              while (1)
                {
                  struct sockaddr in_addr;
                  socklen_t in_len;
                  int infd;
                  char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

                  in_len = sizeof in_addr;
                  infd = accept (sfd, &in_addr, &in_len);
                  if (infd == -1)
                    {
                      if ((errno == EAGAIN) ||
                          (errno == EWOULDBLOCK))
                        {
                          /* We have processed all incoming
                             connections. */
                          break;
                        }
                      else
                        {
                          perror ("accept");
                          break;
                        }
                    }

                  s = getnameinfo (&in_addr, in_len,
                                   hbuf, sizeof hbuf,
                                   sbuf, sizeof sbuf,
                                   NI_NUMERICHOST | NI_NUMERICSERV);
                  if (s == 0)
                    {
                      printf("Accepted connection on descriptor %d "
                             "(host=%s, port=%s)\n", infd, hbuf, sbuf);
                    }

                  /* Make the incoming socket non-blocking and add it to the
                     list of fds to monitor. */
                  s = make_socket_non_blocking (infd);
                  if (s == -1)
                    abort ();

                  event.data.fd = infd;
                  event.events = EPOLLIN | EPOLLET;
                  s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event);
                  if (s == -1)
                    {
                      perror ("epoll_ctl");
                      abort ();
                    }
                }
              continue;
            }
          else
            {
              /* We have data on the fd waiting to be read. Read and
                 display it. We must read whatever data is available
                 completely, as we are running in edge-triggered mode
                 and won't get a notification again for the same
                 data. */
              int done = 0;

              while (1)
                {
                  ssize_t count;
                  char buf[512];

                  count = read (events[i].data.fd, buf, sizeof buf);
                  if (count == -1)
                    {
                      /* If errno == EAGAIN, that means we have read all
                         data. So go back to the main loop. */
                      if (errno != EAGAIN)
                        {
                          perror ("read");
                          done = 1;
                        }
                      break;
                    }
                  else if (count == 0)
                    {
                      /* End of file. The remote has closed the
                         connection. */
                      done = 1;
                      break;
                    }

                  /* Write the buffer to standard output */
                  s = write (1, buf, count);
                  if (s == -1)
                    {
                      perror ("write");
                      abort ();
                    }
                }

              if (done)
                {
                  printf ("Closed connection on descriptor %d\n",
                          events[i].data.fd);

                  /* Closing the descriptor will make epoll remove it
                     from the set of descriptors which are monitored. */
                  close (events[i].data.fd);
                }
            }
        }
    }

  free (events);

  close (sfd);

  return EXIT_SUCCESS;
}
分享到:
评论

相关推荐

    使用epoll开发python服务器

    client.sendall(b'Hello, world') data = client.recv(100) print('Received:', repr(data)) client.close() ``` **总结** `epoll`是提升Python在Linux上开发高性能服务器的关键技术。通过使用`selectors`模块,...

    python使用epoll实现服务端的方法

    send_data = hello world! send_len = len(send_data) recv_len = 1024 tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) addr ...

    python开发总结——c程序员python之路

    print(text.capitalize()) # 输出 "Hello world" ``` - **`center(width)`**:返回一个新字符串,使原字符串居中并使用空格填充至指定宽度。 ```python text = "Python" print(text.center(10)) # 输出 " ...

    分布式键值-redis1

    例如,在执行`SET message "hello world"`时,键`message`就是一个保存字符串"msg"的SDS,而值也是一个保存字符串"hello world"的SDS。 Redis服务器默认配置有16个数据库,每个客户端都可以指定目标数据库进行读写...

    理解Linux进程.pdf

    - **HelloWorld 进程**:介绍了最简单的进程示例——HelloWorld程序。这个程序的作用是在终端输出“HelloWorld”后退出。通过这个简单的示例,读者可以开始了解如何创建和运行一个基本的进程。 - **使用Go语言编写的...

    nginx hello 例子

    这里,我们在 `location /` 中设置了返回 "Hello, World!" 的响应。 3. **启用配置**:创建一个符号链接将新配置文件链接到 `sites-enabled` 目录: ```bash sudo ln -s /etc/nginx/sites-available/hello.conf /...

    swoole4.x框架

    $response-&gt;end("Hello World\n"); }); $server-&gt;start(); ``` 以上代码创建了一个简单的 HTTP 服务器,监听 9501 端口,当收到请求时返回 "Hello World"。 总结,Swoole 4.x 框架极大地扩展了 PHP 的功能,让 ...

    Go的HTTPWeb框架GinWebFramework.zip

     c.String(http.StatusOK, "hello world")  })  router.GET("/ping", func(c *gin.Context) {  c.String(http.StatusOK, "pong")  })  router.POST("/submit", func(c *gin.Context) {  c....

    libevent.pdf

    通过Libevent,你可以实现各种服务器,如简单的"Hello_World"服务器、基于事件的服务器、回显服务器,甚至是HTTP服务器和TCP/IP服务器。这些示例有助于理解如何使用Libevent构建高性能的网络服务。 总结来说,...

    [14本经典Android开发教程]-8-Linux内核阅读心得体会

    读核感悟 Linux内核启动 从hello world说起 3 读核感悟 Linux内核启动 BIOS 5 读核感悟 Linux内核启动 setup辅助程序 6 读核感悟 Linux内核启动 内核解压缩 8 读核感悟 Linux内核启动 开启页面映射 9 读核感悟 Linux...

    Linux内核阅读 经典作品

    其中,“读核感悟”系列文章对这一过程进行了详尽的解析,不仅介绍了内核如何从helloworld程序的视角开始,还深入探讨了BIOS的角色、setup辅助程序的功能以及内核解压缩的机制。特别地,对页面映射的开启与链接脚本...

    LinuxSocketProgrammingbyExample

    书中提供的实例代码不仅仅是简单的Hello World级别的程序,而是涵盖了实际应用中的各种场景,如聊天服务器、文件传输、DNS查询等。通过这些项目,读者可以更深入地理解Socket编程的实际运用。 总之,《Linux Socket...

    httpserver.h:用于在C语言中编写非阻塞HTTP服务器的单个标头库

    例子# define HTTPSERVER_IMPL# include " httpserver.h "# define RESPONSE " Hello, World! "void handle_request ( struct http_request_s* request) { struct http_response_s* response = http_response_init ...

    PHP扩展swoole,PHP7及以上版本可用

    $response-&gt;end("Hello World"); }); $server-&gt;start(); ``` 2. 实现WebSocket服务: ```php $server = new Swoole\WebSocket\Server("127.0.0.1", 9502); $server-&gt;on('open', function ($server, $fd) { ...

    linux内核阅读心得

    ##### 1.1 从Hello World谈起 从最基础的BIOS引导开始,Linux内核的启动过程就像一场精心编排的舞蹈,每一步都紧密相连。最初的引导程序加载内核到内存,并通过一系列的初始化步骤,最终使得内核能够接管系统。 ##...

    linux下C编程

    例如,对于一个简单的“Hello World”程序: ```c int main(int argc, char **argv) { printf("Hello Linux\n"); } ``` 可以通过以下命令进行编译: ```bash gcc -o hello hello.c ``` 这里,`gcc`表示使用GCC...

    tornado中文文档

    例如,`MainHandler` 类在 "Hello, world" 示例中处理根路径("/") 的GET请求。 ```python class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") ``` 3. **Application**...

    Socket C语言的实现.zip

    Socket编程在IT领域中是网络通信的基础,尤其在C语言环境下,它提供了低级别的网络接口,...对于初学者,从简单的"Hello, World!"级别的通信示例开始,逐渐深入到更复杂的网络服务设计,是学习Socket编程的常见路径。

Global site tag (gtag.js) - Google Analytics