epoll的监听多个fd的read和send操作

核心代码如下

m_bRunning = true;
    // first let's increase the limit of open files
	int maxconn = 100000;
	struct rlimit srl;
	srl.rlim_cur = maxconn + 10;
	srl.rlim_max = maxconn + 10;
	if (setrlimit(RLIMIT_NOFILE, &srl) < 0)
	{
		LOG4CXX_FATAL(logger_, "Cannot set RLimit!");
		exit(1);
	}
	epfd = epoll_create(maxconn);

    if (epfd < 0)
    {
        LOG4CXX_FATAL(logger_, "epoll_create error!");
        exit(1);
    }

    // Now let's ignore broken pipes
    struct sigaction sa;
    memset(&sa, 0, sizeof (sa));
    sa.sa_handler = SIG_IGN;
    if (sigaction(SIGPIPE, &sa, NULL) < 0)
    {
        LOG4CXX_WARN(logger_, "Error ignoring SIGPIPE!");
    }

    if (initSockets() < 0)
    {
        exit(1);
    }

    struct epoll_event ev, evs[MAX_EVENTS];
    LOG4CXX_INFO(logger_, "Nethandler started.");
    for (; ; )
    {
		if (!m_bRunning)
		{
			break;
		}
        int count = epoll_wait(epfd, evs, MAX_EVENTS, 10);
        if (count < 0)
        {
            LOG4CXX_FATAL(logger_, "epoll_wait error!");
        }
        time_t now = Clock::getCurrentSystemTime();
        if (!preNetEvent(now))
        {
            LOG4CXX_ERROR(logger_, "PreNetEvent returned false, terminating...");
            break;
        }
        for (int i = 0; i < count; i++)
        {
            int fd = evs[i].data.fd;
            if (isListenSocket(fd))//如果是监听描述符
            {
                struct sockaddr_in sa;
                socklen_t slen = sizeof (sa);
                int nfd = 0;
                nfd = accept(fd, (struct sockaddr*) &sa, &slen);
                if (nfd > 0)
                {
                  //向events中添加新增的文件描述符
                    ev.events = EPOLLIN | EPOLLHUP; //| EPOLLRDHUP;
                    ev.data.fd = nfd;
                    if (epoll_ctl(epfd, EPOLL_CTL_ADD, nfd, &ev) < 0)
                    {
                        LOG4CXX_ERROR(logger_, "epoll_ctl error, cannot add client!");
                    }
                    else
                    {
                        size_t rsize = readCacheSize(fd);
                        //size_t rsize = (fd==wsfd ? NetCache::WEBSERVER_READ_SIZE : NetCache::DEFAULT_READ_SIZE);
                        NetCache *cache = addConnection(nfd, sa, rsize);//添加新的NetCache
                        createProtocolHandler(cache, fd);//设置NetCache类型
                    }
                }
            }
            else // data
            {
                NetCache *cache = getCacheFromFd(fd);
                if (cache != NULL)
                {
                    __uint32_t events = evs[i].events;
                    bool readError = false;
                    if ((events & EPOLLIN) > 0)//如果是可写事件
                    {
                        int64 uid = cache->uid;
                        readError = !cache->read();//读数据并且放入自定义读缓存中
                        if (!readError)
                        {
                            string req;
                            while (cache->assemble(req) && !cache->remove)
                            {
                                //LOG4CXX_DEBUG(logger_, "Command Received: \"" << req.c_str() << "\" from uid:" << uid << " fd:" << fd);

                                if (cache->ph != NULL)
                                {
                                    cache->ph->handle(uid, req);
                                }
                                else
                                {
                                    LOG4CXX_ERROR(logger_, "Protocol handler is NULL for fd:" << fd);
                                }
                            }
                        }
                    }
                    if ((events & EPOLLOUT) > 0)//可写事件
                    {
                        if ( isConnecting( fd ))
                        {
                            connectSuccess( fd );
                        }
                        else if (cache->write())
                        {
                            ev.events = EPOLLIN | EPOLLHUP; // | EPOLLRDHUP;
                            ev.data.fd = fd;
                            epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);
                        }
                    }
                    if ((cache->remove && !cache->waitToWrite()) || readError ||
                            (events & EPOLLHUP) > 0 || //(events&EPOLLRDHUP)>0 ||
                            (events & EPOLLERR) > 0)
                    {
                        int64 uid = cache->uid;
                        if (uid >= 0 && cache->ph != NULL)
                        {
                            cache->ph->leave(uid);
                        }
                        LOG4CXX_DEBUG(logger_, "Client disconnected of fd:" << fd
                                << ", remove: " << cache->remove << ", read error: "
                                << readError << ", hup: " << (events & EPOLLHUP)
                                //<< //", rdhup: " << (events & EPOLLRDHUP) 
                                << ", epoll error: " << (events & EPOLLERR));
                        doCloseConnection(fd);
                        if (isConnectSocket(fd))
                        {
                            connectFailed(fd);
                        }
                    }
                }
                else
                {
                    LOG4CXX_ERROR(logger_, "Cannot find cache for fd:" << fd);
                }
            }
        }
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个使用epoll和本地socket的例子: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <sys/epoll.h> #include <sys/types.h> #include <arpa/inet.h> #include <netinet/in.h> #define MAX_EVENTS 10 #define MAX_BUF_SIZE 1024 int main(int argc, char *argv[]) { int server_fd, client_fd, epoll_fd, n, i; struct epoll_event ev, events[MAX_EVENTS]; struct sockaddr_in server_addr, client_addr; char buf[MAX_BUF_SIZE]; // 创建服务器socket if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(EXIT_FAILURE); } // 绑定服务器地址 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(8888); if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind"); exit(EXIT_FAILURE); } // 监听连接请求 if (listen(server_fd, SOMAXCONN) < 0) { perror("listen"); exit(EXIT_FAILURE); } // 创建epoll实例 if ((epoll_fd = epoll_create1(0)) < 0) { perror("epoll_create1"); exit(EXIT_FAILURE); } // 将服务器socket加入epoll事件 ev.events = EPOLLIN; ev.data.fd = server_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) < 0) { perror("epoll_ctl: server_fd"); exit(EXIT_FAILURE); } while (1) { n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); for (i = 0; i < n; i++) { if (events[i].data.fd == server_fd) { // 有新连接请求 socklen_t client_len = sizeof(client_addr); if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0) { perror("accept"); exit(EXIT_FAILURE); } // 将客户端socket加入epoll事件 ev.events = EPOLLIN; ev.data.fd = client_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) { perror("epoll_ctl: client_fd"); exit(EXIT_FAILURE); } } else { // 有客户端数据可读 memset(buf, 0, MAX_BUF_SIZE); if (read(events[i].data.fd, buf, MAX_BUF_SIZE) < 0) { perror("read"); exit(EXIT_FAILURE); } printf("Received message: %s", buf); // 回复客户端 if (write(events[i].data.fd, buf, strlen(buf)) < 0) { perror("write"); exit(EXIT_FAILURE); } } } } return 0; } ``` 这个例子创建了一个本地socket服务器,监听端口号为8888,使用epoll来处理多个客户端连接。服务器首先创建一个socket并绑定到本地地址,然后监听连接请求。 ### 回答2: epoll是Linux操作系统中用于I/O事件驱动的机制,它可以同时监测多个文件描述符上的事件。本地socket是一种在同一台机器上进行进程间通讯的方法。下面是一个使用epoll和本地socket的例子: 我们假设有一个服务器程序和多个客户端程序运行在同一台机器上。服务器使用本地socket监听客户端的连接请求,客户端通过本地socket与服务器进行通讯。 服务器端代码如下所示: ```c #include <stdio.h> #include <sys/socket.h> #include <sys/epoll.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define MAX_EVENTS 10 #define BUF_SIZE 1024 int main() { int server_sock, client_sock, epoll_fd, event_count, i; struct sockaddr_in server_addr, client_addr; struct epoll_event event, events[MAX_EVENTS]; socklen_t addr_size = sizeof(client_addr); char buf[BUF_SIZE]; // 创建本地socket server_sock = socket(AF_INET, SOCK_STREAM, 0); // 设置服务器地址 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(12345); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定本地socket到服务器地址 bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 监听客户端连接请求 listen(server_sock, 5); // 创建epoll文件描述符 epoll_fd = epoll_create1(0); // 将服务器端socket添加到epoll监听中 event.events = EPOLLIN; event.data.fd = server_sock; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_sock, &event); while (1) { // 启动epoll等待事件 event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); // 处理所有触发的事件 for (i = 0; i < event_count; i++) { // 处理新的客户端连接请求 if (events[i].data.fd == server_sock) { client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &addr_size); // 将新的客户端添加到epoll监听中 event.events = EPOLLIN; event.data.fd = client_sock; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_sock, &event); printf("Client connected: %s\n", inet_ntoa(client_addr.sin_addr)); } // 处理客户端发来的消息 else { memset(buf, 0, sizeof(buf)); recv(events[i].data.fd, buf, BUF_SIZE, 0); printf("Receive message from client: %s\n", buf); } } } // 关闭所有socket和epoll文件描述符 close(server_sock); close(epoll_fd); return 0; } ``` 客户端代码如下所示: ```c #include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define BUF_SIZE 1024 int main() { int client_sock; struct sockaddr_in server_addr; char buf[BUF_SIZE] = "Hello, Server!"; // 创建本地socket client_sock = socket(AF_INET, SOCK_STREAM, 0); // 设置服务器地址 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(12345); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 连接到服务器 connect(client_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 发送消息给服务器 send(client_sock, buf, sizeof(buf), 0); // 关闭socket close(client_sock); return 0; } ``` 以上是一个简单的使用epoll和本地socket的例子。服务器程序使用epoll监听客户端连接请求和处理客户端发来的消息,而客户端程序则使用本地socket连接到服务器并发送消息。 ### 回答3: epoll是一种用于事件通知的高效机制,而本地socket是一种用于进程间通信的方式。它们可以结合使用来实现高效的通信。 一个使用epoll和本地socket的例子是多进程TCP服务器。首先,创建一个本地socket,并将其绑定到一个指定的地址和端口上。然后,创建多个子进程,每个子进程负责处理一个客户端连接。在子进程中,使用epoll监听本地socket和客户端连接上的事件。 当有客户端连接请求到达时,主进程接受该连接请求,并将客户端的socket文件描述符传递给一个子进程。子进程将该socket文件描述符添加到epoll监听列表中。然后,子进程通过epoll的等待事件函数进行监听,并处理已就绪的事件。 当有数据到达时,子进程会收到数据可读事件。子进程通过socket读取数据,并进行相应的处理。当处理完数据后,可以通过socket写回数据给客户端。 通过使用epoll和本地socket,多个客户端连接可以同时被处理,而不需要为每个客户端连接创建一个线程。这种方式避免了线程切换的开销,并提高了服务器的并发性能。 总结来说,使用epoll和本地socket的例子是实现多进程TCP服务器。通过在多个子进程中使用epoll监听本地socket和客户端连接上的事件,可以实现高效的并发通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值