Android上利用epoll机制实现手机服务器?

废话不多数。先上代码。server.cpp

#include <jni.h>
#include <string>
#include <cmath>
#include <sys/epoll.h>
#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include "android/log.h"
#include "jni.h"
#include <pthread.h>

struct epoll_event ev, events[20];
#define LISTENQ 20
#define MAXLINE 5

int main(int argc, char *argv[]) {
    int i, maxi, listenfd, connfd, sockfd, myepfd, nfds, portnumber;
    ssize_t n;
    char line[MAXLINE];
    socklen_t clilen;
    myepfd = epoll_create(58);
    portnumber = 8888;
    struct sockaddr_in clientaddr;
    struct sockaddr_in serveraddr;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    std::cout << "文件描述符为" + std::to_string(listenfd) << std::endl;
    if (listenfd < 0) {
        std::cout << "打开文件错误" + std::to_string(listenfd) << std::endl;
    }
    ev.data.fd = listenfd;
    //设置要处理的事件类型
    ev.events = EPOLLIN | EPOLLOUT;
    epoll_ctl(myepfd, EPOLL_CTL_ADD, listenfd, &ev);

    serveraddr.sin_family = AF_INET;
    char *local_addr = "10.6.25.153";
    inet_aton(local_addr, &(serveraddr.sin_addr));//htons(portnumber);
    serveraddr.sin_port = htons(portnumber);
    bind(listenfd, (sockaddr *) &serveraddr, sizeof(serveraddr));
    listen(listenfd, LISTENQ);


    for (;;) {
        //等待epoll事件的发生

        int nfds = epoll_wait(myepfd, events, 20, -1);
        std::cout << "addr(obj2.pszTestStr) is: " + std::to_string(nfds) << std::endl;
        for (int i = 0; i < nfds; ++i) {
            if (events[i].data.fd == listenfd)//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。

            {
                connfd = accept(listenfd, (sockaddr *) &clientaddr, &clilen);
                if (connfd < 0) {
                    std::cout << "connfd<0" << std::endl;
                    exit(1);
                }
                char *str = inet_ntoa(clientaddr.sin_addr);
                std::cout << "accapt a connection from " << str << std::endl;
                //设置用于读操作的文件描述符
                ev.data.fd = connfd;
                //设置用于注测的读操作事件
                ev.events = EPOLLIN | EPOLLET;
                //注册ev
                epoll_ctl(myepfd, EPOLL_CTL_ADD, connfd, &ev);
            } else if (events[i].events & EPOLLIN)//如果是已经连接的用户,并且收到数据,那么进行读入。

            {
                std::cout << "EPOLLIN" << std::endl;
                if ((sockfd = events[i].data.fd) < 0)
                    continue;
                if ((n = read(sockfd, line, MAXLINE)) < 0) {
                    if (errno == ECONNRESET) {
                        close(sockfd);
                        events[i].data.fd = -1;
                    } else
                        std::cout << "readline error" << std::endl;
                } else if (n == 0) {
                    close(sockfd);
                    events[i].data.fd = -1;
                }
                line[n] = '/0';
                std::cout << "read " << line << std::endl;
                //设置用于写操作的文件描述符

                ev.data.fd = sockfd;
                //设置用于注测的写操作事件

                ev.events = EPOLLOUT | EPOLLET;
                //修改sockfd上要处理的事件为EPOLLOUT

                epoll_ctl(myepfd, EPOLL_CTL_MOD, sockfd, &ev);

            } else if (events[i].events & EPOLLOUT) // 如果有数据发送

            {
                sockfd = events[i].data.fd;
                write(sockfd, line, n);
                //设置用于读操作的文件描述符

                ev.data.fd = sockfd;
                //设置用于注测的读操作事件

                ev.events = EPOLLIN | EPOLLET;
                //修改sockfd上要处理的事件为EPOLIN

                epoll_ctl(myepfd, EPOLL_CTL_MOD, sockfd, &ev);
            }
        }
    }

    return 0;
}

以上为server的代码,我们现在把它编译为能够运行在android手机上。这里要注意下。监听的ip要为自己手机的实际ip地址。可以通过ifconfig查看。如果用本机的“127.0.0.1”会监听不成功。利用android studio的cmake编译系统能够方便的编译。这里我把我的cmakeList贴出来。

add_executable(
        server
        server.cpp
)

另外app的build.gradle 文件中,配置支持c++。

 externalNativeBuild {
            cmake {
                cppFlags "-std=c++11"
            }
        }

实际上主要就是这一句话。现在看下效果。
首先看下服务运行。注意server文件要不能拷贝到sdrcard这类目录运行,因为没有运行权限。
Android上利用epoll机制实现手机服务器?
然后另外一台电脑通过telnet 可以进行socket通信。
Android上利用epoll机制实现手机服务器?
输入字符对应android服务器就可以读取出来了
Android上利用epoll机制实现手机服务器?
大家可以看到,连接建立的时候epoll_wait 会返回,在epoll_event 中我们能够相应的事件。具体epoll的实现原理不细讲了,大家最好还是通过代码来熟悉相关原理比较好。

上一篇:epoll与select


下一篇:MyBatis学习(二)、SQL语句映射文件(2)增删改查、参数、缓存