zoukankan      html  css  js  c++  java
  • ACE 的一些词汇

    事件处理器:
    在类型安全的sigaction()和sigset_t的封装基础之上,捆绑了一种面向对象的、基于事件处理器的信号登记与分派方案,你可以通过 ACE_Sig_Handler类使用这一方案;
    ACE_Sig_Handler类允许客户程序员登记基于ACE_Event_Handler类的对象,在有信号发生的时候被回 调;ACE_Event_Handler类是ACE Reactor框架的中枢,但是在使用ACE_Sig_Handler时,并没有向反映器登记的步骤;

    作为客户程序员,我们必须从ACE_Event_Handler类派生自己的子类,并实现虚方法handle_signal(),以响应信号处理;

    看到好多ACE程序都使用了ACE_NEW_RETURN,一直不知道干嘛用的,再加上前一段时间比较忙,没有对每条语句进行深究。
    今天终于找到了ACE_NEW_RETURN的出处,有三个定义,都在OS_Memory.h中定义,可能是用于适应不同的平台而作的吧。下面 的这个是最容易看懂的,用了try-catch语句。
     
    #    define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
       do { try { POINTER = new CONSTRUCTOR; } \
            catch (ACE_bad_alloc) { errno = ENOMEM; POINTER = 0; return RET_VAL; } \
       } while (0)
     
    ACE_NEW_RETURN的定义是:
    ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL)
    ACE_NEW_RETURN对应翻译是:
    try
    {
          POINTER=new CONSTRUCTOR;
    }
    catch(ACE_bad_alloc)
    {
           errno=ENOMEM;
           POINTER=0;
           return RET_VAL;
    }
    意思就是用new动态生成一个参数2类型的空间,并将空间的首地址副给第一个参数。如果有错误产生则将第一个参数的值设为空,并返回值 RET_VAL。不过不知道为什么Doung为什么喜欢在副值之前用do-while语句,莫非这样做有什么好处?
    另两个定义是
    #    define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
       do { POINTER = new (ACE_nothrow) CONSTRUCTOR; \
         if (POINTER == 0) { errno = ENOMEM; return RET_VAL; } \
       } while (0)
    # define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
       do { POINTER = new CONSTRUCTOR; \
         if (POINTER == 0) { errno = ENOMEM; return RET_VAL; } \
       } while (0)
     

    ACE_Message_Block

    ACE_Message_Block在 Ace中用来表示消息的存放空间,可用做网络通信中的消息缓冲区,使用非常频繁,下面将在如下方简单的介绍一下ACE_Message_Block相 关功能。

    1. 创建消息块
    2. 释放消息块
    3. 从消息块中读写数据
    4. 数据的拷贝
    5. 其它常用函数

    1。创建消息块

    创建消息块的方式比较灵活,常用的有以下几种方式 :

    1。直接给消息块分配内存空间创建。

        ACE_Message_Block *mb = new ACE_Message_Block (30);

    2。共享底层数据块创建。

        char buffer[100];
        ACE_Message_Block *mb = new ACE_Message_Block (buffer,30);

    这种方式共享底层的数据块,被创建的消息块并不拷贝该数据,也不假定自己拥有它的所有权。在消息块mb被销毁时,相关联的数据缓冲区data将不会被销毁。这是有意义的:消息块没有拷贝 数据,因此内存也不是它分配的,这样它也不应该负责销毁它。

    3。通过duplicate()函数从已有的消息块中创建副本。

        ACE_Message_Block *mb = new ACE_Message_Block (30);
        ACE_Message_Block *mb2 = mb->duplicate();

    这种方式下,mb2和mb共享同一数据空间,使用的是ACE_Message_Block的引用计数机制。它返回指向要被复制的消息块的 指针,并在内部增加内部引用计数

    4。通过clone()函数从已有的消息块中复制。

        ACE_Message_Block *mb = new ACE_Message_Block (30);
        ACE_Message_Block *mb2 = mb->clone();

    clone()方法实际地创建整个消息块的新副本,包 括它的数据块和附加部分;也就是说,这是一次"深拷贝"。

    2。释放消息块

    一旦使用完消息块,程序员可以调用它的release()方法来释放它。

    1. 如果消息数据内存是由该消息块分配的,调用release()方法就也会释放此内存。
    2. 如果消息块是引用计数的,release()就会减少计数,直到到达0为止;之后消息块和与它相关联的数据块才从内存中被移除。
    3. 如果消息块是通过共享已分配的底层数据块创建的,底层数据块不会被释放。

    无论消息块是哪种方式创建的,只要在使用完后及时调用release()函数,就能确保相应的内存能正确的释放。

    3。从消息块中读写数据

    ACE_Message_Block提 供了两个指针函数以供程序员进行读写操作,rd_ptr()指向可读的数据块地址,wr_ptr()指向可写的数据块地址,默认情况下都执行数据块的首地址。下面的例子简单了演示它的 使用方法。

    #include "ace/Message_Queue.h"
    #include "ace/OS.h"

    int main(int argc, char *argv[])
    {
        ACE_Message_Block *mb = new ACE_Message_Block (30);
        ACE_OS::sprintf(mb->wr_ptr(),"%s","hello");
        ACE_OS::printf("%s\n",mb->rd_ptr ());
        mb->release();
        return 0;
    }

    注意:这两个指针所指向的位置并不会自动移动, 在上面的例子中,函数执行完毕后,执行的位置仍然是最开始的0,而不是最新的可写位置5,程序员需要通过wr_ptr(5)函数手动移 动写指针的位置。

    4。数据的拷贝

    一般的数据的拷贝可以通过函数来实现数据的拷贝,copy()还会保证wr_ptr()的更新,使其指向缓冲区的新末尾处。

    下面的例子演示了copy()函数的用法。

        mb->copy("hello");
        mb->copy("123",4);

    注意:由于c++是以'\0'作为字符串结束标志的,对于上面的例子,底层数据块中保存的是"hello\0123\0", 而用ACE_OS::printf("%s\n",mb->rd_ptr ());打印出来的结果是"hello", 使用copy函数进行字符串连接的时候需要注意。

    5。其它常用函数

    1. length()    返回当前的数据长度
    2. next()    获取和设置下一个ACE_Message_Block的链接。(用来建立消息队列非常有用)
    3. space()    获取剩余可用空间大小
    4. size()    获取和设置数据存储空间大小。
     

     siginfo_t介绍:
    这个结构用于存放更多的关于信号的信息,它说明了正在递送的信号的起因及属性;取决于捕捉到的信号,siginfo_t结构里面存放的信息的含义会发生变 化;基本上所有收到的信号都有si_signo、si_errno和si_code信息可用;
    si_code成员告诉我们的是该信号的发送原因;有些值是真对特定信号的,而另外一些值则与所有信号都有关系;有时候我们必须对信号的值进行检查,以确 定siginfo_t的哪些部分是适用的,比如:si_address属性只适用于信号SIGILL、SIGFPE、SIGSEGV和 SIGBUS.siginfo_t的si_address属性描述的是引发信号的内存位置;

    ACE_Task::putq
    2008年12月08日 星期一 下午 05:03
    int ACE_Task< ACE_SYNCH_DECL >::putq (     ACE_Message_Block * , ACE_Time_Value *     timeout = 0    )    

    提供了一个向线程中提交数据的方法

    它是通过将提交数据插入到线程的消息队列来(msg_queue)完成这个操作的,我起初认为这个方法是完全异步的,也就是说调用时不会阻塞,但最近在使 用线程池时,发现,如果msg_queue已满,则会阻塞,阻塞时时间长度,由putq的第二个参数来决定。
    调用putq时,向msg_queue添加数据(enqueue_tail),而在线程中,getq时,从队列中弹出(dequeue_head),每次 调用enqueue_tail时,msg_queue都方法:is_full_i()来判断队列是否已满,在is_full_i()中,是通过判断队列中 所有数据块的总长度来确定是否已满的,而不是通过数据块个数:this->cur_bytes_ >= this->high_water_mark_

    以下为putq及相关数据的代码:
    template <ACE_SYNCH_DECL> ACE_INLINE int
    ACE_Task<ACE_SYNCH_USE>::putq (ACE_Message_Block *mb, ACE_Time_Value *tv)
    {
    ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::putq");
    return this->msg_queue_->enqueue_tail (mb, tv); //直接添加到队列
    }



    template <ACE_SYNCH_DECL> int
    ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_tail (ACE_Message_Block *new_item,
                                                  ACE_Time_Value *timeout)
    {
       ...

        if (this->wait_not_full_cond (ace_mon, timeout) == -1) //检测并确保队列未满
          return -1;

        queue_count = this->enqueue_tail_i (new_item); //添加新数据块
    ...

    }



    template <ACE_SYNCH_DECL> int
    ACE_Message_Queue<ACE_SYNCH_USE>::wait_not_full_cond (ACE_Guard<ACE_SYNCH_MUTEX_T> &,
                                                          ACE_Time_Value *timeout)
    {
    ...
    while (this->is_full_i ()) //决断队列是否已满
        {
          if (this->not_full_cond_.wait (timeout) == -1) //等侍队列有数据块弹出
            {
    ...
            }
    ...
        }
    ...
    }


    template <ACE_SYNCH_DECL> int
    ACE_Message_Queue<ACE_SYNCH_USE>::is_full_i (void)
    {
    ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::is_full_i");
    return this->cur_bytes_ >= this->high_water_mark_; //cur_bytes的值在是所有数据块长度的和, high_water_mark_的默认值为:0x4000,可以在能过方法high_water_mark()来修改,在 ACE_Message_Queue::open时,可以通过参数指定.
    }


     

    ACE_SOCK_Connector和ACE_SOCK_Acceptor 收藏

    对于面向连接的网络应用程序,一般 都存在两种角色。server和client,或者说connector和acceptor。

    ACE就是将socket中的tcp部分按照这两种角色划分的。一个ACE_SOCK_ConnectorACE_SOCK_Acceptor。在这两个角色中间,有一个中间人--ACE_SOCK_Stream起通讯的作用。
    换一种方式来说,ACE_SOCK_Stream相当于原来的file descriptor,ACE_SOCK_Connector相当于connect函数,ACE_SOCK_Acceptor相当于accept函数。ACE将与之相伴的函数调用全部封装起来。剩下这两个调用。
    另外还有一个ACE_INET_Addr,相当于sockaddr_in(还可以作为 sockaddr_in6,不过还用不到),提供了许多构造函数用于。
    详细内容里是两个最最简单的client、server程序。

    // client.cpp
    #include <ace/SOCK_Connector.h>
    #include <ace/INET_Addr.h>
    #include <ace/Log_Msg.h>
    #include <iostream>
    #include <cstdlib>

    using namespace std;

    int main(int argc, char** argv)
    {
    if (argc < 3) {
    cout << "usage: client <host> <port>" << endl;
    exit(1);
    }
    ACE_INET_Addr remote_addr(atoi(argv[2]), argv[1]);
    // 构造一个sockaddr_in,并memset..
    // 然后调用一些我也记不住的函数把字符串地址转为ip地址..
    // 当然,htons之类的也是必不可少,全部被搞定了..
    ACE_SOCK_Connector connector;
    // 缺省构造函数什么都不作,当然也可以直接用构造函数connect
    // 用法和成员函数connect相同..
    ACE_SOCK_Stream stream;
    // 这个构造函数也是什么都不错,太懒了...
    char buf[BUFSIZ];

    if (connector.connect(stream, remote_addr) == -1)
    ACE_ERROR_RETURN((LM_ERROR, "(%P|%t) %p\n", "connection failed"), -1);
    // connect就是重头戏了,他先调用ACE_SOCK_Stream的open函数..
    // 也就相当于调用::socket..
    // 有需要的话再调用一下::bind,然后就::connect了..
    for (ssize_t n; (n = stream.recv(buf, sizeof buf)) > 0;)
    ACE::write_n(ACE_STDOUT, buf, n);
    // 然后就是从stream里的file descriptor读东东了..
    // 这些可都是inline函数哦..
    }

    // server.cpp
    #include <iostream>
    #include <ace/INET_Addr.h>
    #include <ace/SOCK_Acceptor.h>
    #include <ace/Log_Msg.h>
    using namespace std;

    int main(int argc, char** argv)
    {
    if (argc != 2) {
    cout << "usage: server <port>\n";
    exit(1);
    }

    ACE_INET_Addr server_addr(atoi(argv[1]));
    ACE_SOCK_Acceptor acceptor(server_addr);
    // 不能再让构造函数这么懒了,给他参数叫他去调用open
    // 也就是 ::socket和 ::bind...
    ACE_SOCK_Stream stream;
    ACE_INET_Addr client_addr;
    char buf[] = "server sended message\n";

    while (1)
    {
    if (acceptor.accept(stream, &client_addr) == -1)
    ACE_ERROR((LM_ERROR, "%p\n", "accept"));
    // 开始accept了,会设置stream的handle为新的连接...
    else if (stream.send_n(buf, strlen(buf) + 1, 0) == -1)
    ACE_ERROR_RETURN((LM_ERROR, "(%P|%t) %p\n", "send"), 0);
    if (stream.close() == -1)
    ACE_ERROR_RETURN((LM_ERROR, "(%P|%t) %p\n", "close"), 0);
    }
    return 0;
    }

  • 相关阅读:
    jsp Ajax请求(返回xml数据类型)
    springboot整合mybatis
    springboot使用jdbcTemplate案例
    springboot使用jpa案例
    使用SpringBoot访问jsp页面
    SpringBoot使用thymeleaf案例
    SpringBoot
    Dobbox
    Spring Jpa
    SSM整合Dubbo登陆案例
  • 原文地址:https://www.cnblogs.com/xianqingzh/p/1733037.html
Copyright © 2011-2022 走看看