epoll例程(网上找的)

/***
  This file is part of systemd.

  Copyright 2012 Lennart Poettering

  systemd is free software; you can redistribute it and/or modify it
  under the terms of the GNU Lesser General Public License as published by
  the Free Software Foundation; either version 2.1 of the License, or
  (at your option) any later version.

  systemd is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

#include <string.h>

#include "alloc-util.h"
#include "string-util.h"
#include "util.h"

#include "socket-util.h"


static void test_should_pass(const char *p) {
        usec_t t, q;
        char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *sp;

        assert_se(parse_timestamp(p, &t) >= 0);
        format_timestamp_us(buf, sizeof(buf), t);
        log_info("%s", buf);

        /* Chop off timezone */
        sp = strrchr(buf, ' ');
        assert_se(sp);
        *sp = 0;

        assert_se(parse_timestamp(buf, &q) >= 0);
        assert_se(q == t);

        format_timestamp_relative(buf_relative, sizeof(buf_relative), t);
        log_info("%s", strna(buf_relative));
        assert_se(parse_timestamp(buf, &q) >= 0);
}

static void test_should_parse(const char *p) {
        usec_t t;

        assert_se(parse_timestamp(p, &t) >= 0);
}

static void test_should_fail(const char *p) {
        usec_t t;

        assert_se(parse_timestamp(p, &t) < 0);
}

static void test_one(const char *p) {
        _cleanup_free_ char *with_utc;

        log_info("Test: %s", p);
        with_utc = strjoin(p, " UTC", NULL);
        test_should_pass(p);
        test_should_pass(with_utc);
}

static void test_one_noutc(const char *p) {
        _cleanup_free_ char *with_utc;

        log_info("Test: %s", p);
        with_utc = strjoin(p, " UTC", NULL);
        test_should_pass(p);
        test_should_fail(with_utc);
}


int main1(int argc, char *argv[]);

int main1(int argc, char *argv[]) {
        test_one("17:41");
        test_one("18:42:44");
        test_one("18:42:44.0");
        test_one("18:42:44.999999999999");
        test_one("12-10-02 12:13:14");
        test_one("12-10-2 12:13:14");
        test_one("12-10-03 12:13");
        test_one("2012-12-30 18:42");
        test_one("2012-10-02");
        test_one("Tue 2012-10-02");
        test_one_noutc("now");
        test_one("yesterday");
        test_one("today");
        test_one("tomorrow");
        test_one_noutc("+2d");
        test_one_noutc("+2y 4d");
        test_one_noutc("5months ago");
        test_one_noutc("@1395716396");
        test_should_parse("today UTC");
        test_should_fail("today UTC UTC");

        return 0;
}

#include <stdio.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>

#define MAX_EVENT 20
#define READ_BUF_LEN 256


extern void hexdump_debug (unsigned long bse, char *buf, int len);

void hexdump_debug (unsigned long bse, char *buf, int len)
{
  int pos;
  char line[80];

  while (len > 0)
    {
      int cnt, i;

      pos = snprintf (line, sizeof (line), "%08lx  ", bse);
      cnt = 16;
      if (cnt > len)
    cnt = len;

      for (i = 0; i < cnt; i++)
    {
      pos += snprintf (&line[pos], sizeof (line) - pos,
                "%02x ", (unsigned char) buf[i]);
      if ((i & 7) == 7)
        line[pos++] = ' ';
    }

      for (; i < 16; i++)
    {
      pos += snprintf (&line[pos], sizeof (line) - pos, "   ");
      if ((i & 7) == 7)
        line[pos++] = ' ';
    }

      line[pos++] = '|';

      for (i = 0; i < cnt; i++)
    line[pos++] = ((buf[i] >= 32) && (buf[i] < 127)) ? buf[i] : '.';

      line[pos++] = '|';

      line[pos] = 0;

      printf ("%s\n", line);

      /* Print only first and last line if more than 3 lines are identical.  */
      if (len >= 4 * 16
      && ! memcmp (buf, buf + 1 * 16, 16)
      && ! memcmp (buf, buf + 2 * 16, 16)
      && ! memcmp (buf, buf + 3 * 16, 16))
    {
      printf ("*\n");
      do
        {
          bse += 16;
          buf += 16;
          len -= 16;
        }
      while (len >= 3 * 16 && ! memcmp (buf, buf + 2 * 16, 16));
    }

      bse += 16;
      buf += 16;
      len -= cnt;
    }
}


/**
 * 设置 file describe 为非阻塞模式
 * @param fd 文件描述
 * @return 返回0成功,返回-1失败
 */
static int make_socket_non_blocking (int fd) {
    int flags, s;
    // 获取当前flag
    flags = fcntl(fd, F_GETFL, 0);
    if (-1 == flags) {
        perror("Get fd status");
        return -1;
    }

    //printf( "flags = 0x%x\n", flags );
    

    flags |= O_NONBLOCK;
    //printf( "flags = 0x%x\n", flags );

    // 设置flag
    s = fcntl(fd, F_SETFL, flags);
    if (-1 == s) {
        perror("Set fd status");
        return -1;
    }
    return 0;
}


int main(int argc, char *argv[]) 

    //epoll 实例 file describe
    int epfd = 0;
    int listenfd = 0;
    int result = 0;
    struct epoll_event ev, event[MAX_EVENT];
    // 绑定的地址
    const char * const local_addr = "192.168.1.105";
    struct sockaddr_in server_addr = { 0 };
       
    union sockaddr_union snl;
    socklen_t addrlen;
    int r;
    char *p;

           

    listenfd = socket(AF_INET, SOCK_STREAM, 0);


    //listenfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT); 
    if (-1 == listenfd) {
        perror("Open listen socket");
        return -1;
    }
    /* Enable address reuse */
    int on = 1;
    // 打开 socket 端口复用, 防止测试的时候出现 Address already in use
    result = setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
    if (-1 == result) {
        perror ("Set socket");
        return 0;
    }

    server_addr.sin_family = AF_INET;
    printf( "sizeof(server_addr.sin_addr) = %d\n", sizeof(server_addr.sin_addr) );

    hexdump_debug(0, &server_addr.sin_addr, sizeof(server_addr.sin_addr));

    inet_aton (local_addr, &(server_addr.sin_addr));
    hexdump_debug(0, &server_addr.sin_addr, sizeof(server_addr.sin_addr));
    
    server_addr.sin_port = htons(8080);
    result = bind(listenfd, (const struct sockaddr *)&server_addr, sizeof (server_addr));
    if (-1 == result) {
        perror("Bind port");
        return 0;
    }
    result = make_socket_non_blocking(listenfd);
    if (-1 == result) {
        return 0;
    }

    result = listen(listenfd, 200);
    if (-1 == result) {
        perror("Start listen");
        return 0;
    }

    // 创建epoll实例
    epfd = epoll_create1(0);
    if (1 == epfd) {
        perror("Create epoll instance");
        return 0;
    }

    ev.data.fd = listenfd;
    ev.events = EPOLLIN | EPOLLET /* 边缘触发选项。 */;
    // 设置epoll的事件
    result = epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);

    if(-1 == result) {
        perror("Set epoll_ctl");
        return 0;
    }

    for ( ; ; ) {
        int wait_count;
        // 等待事件
        wait_count = epoll_wait(epfd, event, MAX_EVENT, -1);
        printf( "wait_count = %d\n", wait_count );
        for (int i = 0 ; i < wait_count; i++) {
            uint32_t events = event[i].events;
            // IP地址缓存
            char host_buf[NI_MAXHOST];
            // PORT缓存
            char port_buf[NI_MAXSERV];

            int __result;
            // 判断epoll是否发生错误


            printf( "event[i].data.fd = %d\n", event[i].data.fd );
            
            if ( events & EPOLLERR || events & EPOLLHUP || (! events & EPOLLIN)) {
                printf("Epoll has error\n");
                close (event[i].data.fd);
                continue;
            } else if (listenfd == event[i].data.fd) {
                // listen的 file describe 事件触发, accpet事件

                for ( ; ; ) { // 由于采用了边缘触发模式,这里需要使用循环
                    struct sockaddr in_addr = { 0 };
                    socklen_t in_addr_len = sizeof (in_addr);
                    int accp_fd = accept(listenfd, &in_addr, &in_addr_len);


                    printf( "accp_fd = %d\n", accp_fd );
                    if (-1 == accp_fd) {
                        //perror("Accept123");
                        break;
                    }else{
                        //perror("Accept456");

                    }
                    /* get the address the kernel has assigned us
                     * it is usually, but not necessarily the pid
                     */ 
                    //addrlen = sizeof(struct sockaddr_in);
                    //printf( "sizeof(snl) = %d\n", sizeof(snl) );
                    //printf( "accp_fd = %d\n", accp_fd );
                    //hexdump_debug(0, &snl.in, addrlen);
                    //printf( "addrlen = %d\n", addrlen );
                    //r = getsockname(accp_fd, &snl.in, &addrlen);       
                    //printf( "addrlen = %d\n", addrlen );
                    //printf( "r = %d\n", r );
                    //hexdump_debug(0, &snl.in, addrlen);
                    //获取与文件句柄所绑定的套接字的ip地址
                    //即本机地址 或者是进程的pid(如果是系统内部通讯,应用与内核之间的通讯)
    
                    __result = getnameinfo(&in_addr, sizeof (in_addr),
                                           host_buf, sizeof (host_buf) / sizeof (host_buf[0]),
                                           port_buf, sizeof (port_buf) / sizeof (port_buf[0]),
                                           NI_NUMERICHOST | NI_NUMERICSERV);
                    //显示来连接此服务器的客户端的ip地址与端口号
                    //通过accept得到客户端的ip地址与端口号
                    if (! __result) {
                        printf("New connection: host = %s, port = %s\n", host_buf, port_buf);
                    }

                    __result = make_socket_non_blocking(accp_fd);
                    if (-1 == __result) {
                        return 0;
                    }

                    ev.data.fd = accp_fd;
                    ev.events = EPOLLIN | EPOLLET;
                    // 为新accept的 file describe 设置epoll事件
                    __result = epoll_ctl(epfd, EPOLL_CTL_ADD, accp_fd, &ev);

                    if (-1 == __result) {
                        perror("epoll_ctl");
                        return 0;
                    }
                }
                continue;
            } else {
                // 其余事件为 file describe 可以读取
                int done = 0;
                // 因为采用边缘触发,所以这里需要使用循环。如果不使用循环,程序并不能完全读取到缓存区里面的数据。
                for ( ; ;) {
                    ssize_t result_len = 0;
                    char buf[READ_BUF_LEN] = { 0 };

                    result_len = read(event[i].data.fd, buf, sizeof (buf) / sizeof (buf[0]));

                    if (-1 == result_len) {
                        if (EAGAIN != errno) {
                            perror ("Read data");
                            done = 1;
                        }
                        break;
                    } else if (! result_len) {
                        done = 1;
                        break;
                    }

                    write(STDOUT_FILENO, buf, result_len);
                }
                if (done) {
                    printf("Closed connection\n");
                    close (event[i].data.fd);
                }
            }
        }

    }
    close (epfd);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值