select多路复用 : EasyMouse的通道模式设计(下)

来源:互联网 发布:站长之家域名ip查询 编辑:程序博客网 时间:2024/05/20 08:45

此文章源自于EasyMouse项目实践中的设计框架,EasyMouse是一款安卓无线鼠标、键盘软件,可以让你的手机当做鼠标和键盘,远程操作电脑。

欢迎下载使用: EasyMouse官网!


select多路复用 : EasyMouse的通道模式设计(上)


监听通道处理OnChannelForTcp

所有新接入的链接都会进行此函数进行处理。此函数只负责建立相应的通道,不负责处理任何数据;

void OnChannelForTcp(Channel* pChl)

{

    ASSERT(pChl);

    // 新建一个通道

    pChannel pNewChl = new Channel();

    int addr_len = sizeof(pNewChl->addr);

    pNewChl->socket = accept(pChl->socket, &pNewChl->addr, &addr_len);

    if (pNewChl->socket < 0){

        // something error, 

        }

 

    pNewChl->type = CHANNEL_TYPE_UNKNOW;// 所有新建连接通道为未识别

    pNewChl->pfunc = OnChannelForUnknow;// 未识别通道处理函数

    pNewChl->ip  = inet_ntoa(pNewChl->addr.sin_addr);

    /* 这里你还可以做一些其他的初始化,如接入时间等 */


    g_Channel.push_back(pNewChl);// 加入全局通道列表

}

 

说明:

1, 你看到我们有很多个地方调用g_Channel.push_back(pChl);的方式,其实这里应该封装一些函数专门用来操作g_Channel全局变量,并做好线程互斥。因为这个变量将会有多个线程操作,如设备断开连接的时候,可能需要删除相应的通道;

2, OnChannelForUdp的回调,这里不做介绍。EasyMouse主要是接收广播包,并回复即可;

 

未知通道处理OnChannelForUnknow

    此通道处理函数,主要负责通道类型的识别过程。当一个新的客户端接入的时候,OnChannelForTcp将通过accept立即创建一个未知通道(如上),并且此通道的连接马上进行监听序列,因此理论上这个连接后的数据将立即进入这个通道处理,如登陆认证...

void OnChannelForUnknow(Channel* pChl)

{

    // 定义一个你封装的协议包

    ProtoPack pack;

    if (pack.recv(pChl) <= 0){// 通过你封装的接口,从通道接收一个完整的协议包

        // something error, maybe return;

    }

     

    /* 这里需要对收到的协议数据做安全监测,避免错误的数据导致程序崩溃 */

    switch(pack.service()){// pack.service() 获取链接第一个包的类型

        case MAYBE_LOGIN:// 也许是新客户端接入,做登陆认证

            // 这里做必要的校验处理,如用户名,密码是否正确,获取终端名,系统等

            pChl->type = CHANNEL_TYPE_CMD;// 识别成功,转换为命令通道;

            pChl->pfunc = OnChannelForCmd;// 重要

            // 发送回包告诉客户端是否登录成功

            break;

        case MAYBE_SEND_FILE:

            // 解析pack.body获取文件名,大小等信息。创建线程来处理此通道

            pChl->pid = pthread_create();

            pChl->type = CHANNEL_TYPE_DATA;// 识别成功,转换为数据通道;

            pChl->pfunc = NULL;

            // 发送回包,告诉客户端是否准备好接收文件了。

            break;

        default:

            // something error;

    }

}

 

命令通道处理OnChannelForCmd

    这里没有伪代码,你需要根据自己的服务器提供的功能来处理客户端的请求。通过上面的设计模式。当客户端连接服务器,并通过认证之后。接入连接转换为命令通过,客户端所有的服务请求都可以通过这条连接发送请求,并将进入这里进行处理;

 

说明:

这里主要是接收协议包,处理请求。如果需要响应的话,就往命令通道发送回包即可;

 

数据通道处理OnChannelForData

数据通道我们是通过线程来处理的。因此不会进行监听序列,你可以看到在服务器主循环逻辑中有排除数据通道if ((*itr)->type != CHANNEL_TYPE_DATA);

 

数据通道线程处理完文件等类似的数据接收之后,直接关闭数据通道(从全局链表g_Channel删除),所有需要封装一些函数来对g_Channel进行访问,并实现互斥的功能;

数据通道处理线程没接收到一个数据包之后,直接调用此通道的回调函数OnChannelForData处理即可,如保存到文件中;

 

 

效果体验

你可以到EasyMouse官网下载此软件体验整个逻辑实现的效果,包括EmServer服务器端,EasyMouse安卓应用。

你可以同时接入多个手机,认证登陆,服务器端和客户端同时互传文件等;

0 0
原创粉丝点击