Skip to content
chishaxie edited this page Jan 5, 2014 · 9 revisions
  • 以下全部内容均在ccf命名空间中
  • 事件API又称功能API,事件API越丰富也意味着功能越丰富
  • 一般情况,事件API应该和awaitall_ofany_of配合,组合逻辑分别为await某事件all_of某些事件any_of某些事件
  • 若你需要等待某事件则为await(某事件)
  • 若你需要等待某些事件则为await(all_of(某事件,某事件,...))
  • 若你需要等待某些事件其中之一则为await(any_of(某事件,某事件,...))
  • 示例:你需要等待两个udp的recv事件,并且需要设置一个超时时间,则你可以用使用:

await(
    any_of(
        all_of(
            udp0.recv,
            udp1.recv
        ),
        sleep(x ms)
    )
)

sleep 休息

class sleep : public event_task
{
public:
    sleep(uint64 timeout); //ms
    virtual ~sleep();
}
  • sleep(uint64 timeout); 参数为休息的毫秒数
  • 该task在会等待timeout毫秒,timeout毫秒后则执行完毕

sync 同步(类似信号)

class sync : public event_task
{
public:
    sync();
    sync(long id); //unique
    virtual ~sync();
    static int notify(sync* obj);
    static int notify(long id);
}
  • sync(); 创建匿名同步事件
  • sync(long id); 创建命名同步事件(其命名id为long整数)
  • static int notify(sync* obj); 通知某同步事件(一般用于通知匿名同步事件)
  • static int notify(long id); 通知某命名事件(通过其id号通知)
  • 该task在会一直等待被通知,接受到通知后,则执行完毕
  • 若没有对应的对象在等待被通知,则notify函数不会有任何作用
  • 同一命名同步事件,只能存在一个对象

网络事件相关回调函数

template<typename SeqType>
typedef int seq_getter(const void* buf, size_t size, SeqType* seq);
  • 序列号获取回调函数(udp/tcp)
  • 注:上面的写法实际上C++语法不支持(仅供理解)
  • buf 数据包起点指针(传入参数)
  • size 数据包长度(传入参数)
  • seq *seq需要赋上序列号的值(传出参数)
  • 返回: >=0,成功 <0,失败

template<typename SeqType>
typedef void pkg_seq_unrecv(const void* buf, size_t size, const SeqType& seq);
  • 数据包该seq未被recv回调函数(udp/tcp)
  • 注:上面的写法实际上C++语法不支持(仅供理解)
  • buf 数据包起点指针(传入参数)
  • size 数据包头长度(传入参数)
  • seq 序列号(传入参数)

typedef void pkg_seq_failed(const void* buf, size_t size, int ret);
  • 数据包seq获取失败回调函数(udp/tcp)
  • buf 数据包起点指针(传入参数)
  • size 数据包头长度(传入参数)
  • ret 获取seq失败时的返回码

typedef size_t len_getter(const void* buf, size_t size);
  • 包长度获取回调函数(tcp,通过包头获取整个包的长度)
  • buf 数据包起点指针(传入参数)
  • size 数据包头长度(传入参数)
  • 返回: 数据包的长度(若小于包头长度或大于最大长度都视为错误)

typedef void pkg_ignored(const void* buf, size_t size, const struct sockaddr* addr);
  • 被忽略的数据包回调函数(udp)
  • buf 数据包起点指针(传入参数)
  • size 数据包头长度(传入参数)
  • addr 数据包的源地址(支持IPv4/IPv6,需转型至sockaddr_in/sockaddr_in6)

udp

class udp
{
public:
    udp();
    ~udp();
    int bind(const struct sockaddr_in& addr);
    int bind(const struct sockaddr_in6& addr, bool ipv6_only = false);
    template<typename SeqType>
    int bind(seq_getter* getter, pkg_seq_unrecv* unrecv = NULL, pkg_seq_failed* failed = NULL);
    template<typename Compare, typename SeqType>
    int bind(seq_getter* getter, pkg_seq_unrecv* unrecv = NULL, pkg_seq_failed* failed = NULL);
    void ignore_recv(pkg_ignored* ignored = NULL);
    unsigned long long count_unrecv() const;
    unsigned long long count_failed() const;
    unsigned long long count_ignored() const;
    static const void* internal_buffer(size_t& len);
}
  • 注: udp类不是task的子类
  • udp对象逻辑上和一个udp fd对应
  • int bind(const struct sockaddr_in& addr); 绑定IPv4地址(若不绑定则使用随机端口),返回0成功
  • int bind(const struct sockaddr_in6& addr, bool ipv6_only = false); 绑定IPv6地址(若不绑定则使用随机端口),返回0成功
  • int bind(seq_getter* getter, pkg_seq_unrecv* unrecv = NULL, pkg_seq_failed* failed = NULL); 绑定seqer,返回0成功
  • getter 序列号获取回调函数(全部udp收包都需要调用该函数)
  • unrecv 序列号未被recv的回调函数
  • failed 序列号获取失败的回调函数
  • 该函数为模板函数,其中序列号的类型为模板类型(即任意类型),另可额外设置序列号类型的比较函数(如bind(...))
  • void ignore_recv(pkg_ignored* ignored = NULL); 忽略全部收包(用于不关注回包的场合,回调函数可用于日志监控等)
  • unsigned long long count_unrecv() const; 获取当前序列号未被recv的计数
  • unsigned long long count_failed() const; 获取当前获得序列号失败的计数
  • unsigned long long count_ignored() const; 获取当前被忽略的数据包的计数
  • static const void* internal_buffer(size_t& len); 返回当前内部Buffer(参数为传出参数,len值会等于Buffer长度)
  • 若udp对象绑定了seqer则会使用内部Buffer(全部udp接收复用同一Buffer,注意有效期)
  • 使用了内部Buffer时,全部接收的数据包会先放到内部Buffer上,再获取其seq,并路由至对应的事件
  • 若udp对象绑定了seqer,收到数据包会进行seq获取匹配并优先被recv_by_seq事件捕获,未被匹配seq的和获取seq失败的数据包将优先被recv事件捕获,剩余的则会触发unrecv或failed回调
  • 接收数据包的优先级为udp::recv_by_seq事件 > udp::recv事件 > unrecv/failed回调

udp::send 发送

class send : public event_task
{
public:
    send(udp& handle, const struct sockaddr_in& addr, const void* buf, size_t len);
    send(udp& handle, const struct sockaddr_in6& addr, const void* buf, size_t len);
    virtual ~send();
}
  • 注: 该类是udp类的内部public类
  • 构造函数参数分别为udp对象,目标IPv4/IPv6地址,数据包起点,数据包长度
  • 该task会等待udp对象中的fd可写时发送数据包
  • 注意: 该task是不可中断的(详见取消模型)

udp::recv udp接收

class recv : public event_task
{
public:
    recv(udp& handle, void* buf, size_t& len);
    virtual ~recv();
    uint16 peer_type();
    struct sockaddr_in peer_addr_ipv4();
    struct sockaddr_in6 peer_addr_ipv6();
}
  • 注: 该类是udp类的内部public类
  • 构造函数参数分别为udp对象,数据包起点,数据包长度(传入传出参数)
  • 该task会等待udp对象中的fd可读时接收数据包并写到buf中
  • 若绑定了seqer,则buf参数可以为NULL,内部Buffer接收后将不会拷贝到buf上,可通过udp::internal_buffer函数获取Buffer
  • uint16 peer_type(); 获取对端类型(返回AF_INET/AF_INET6)
  • struct sockaddr_in peer_addr_ipv4(); 获取对端IPv4地址(需确保对端类型为AF_INET)
  • struct sockaddr_in6 peer_addr_ipv6(); 获取对端IPv6地址(需确保对端类型为AF_INET6)

udp::recv_by_seq 接收(通过seq)

template<typename SeqType = uint32>
class recv_by_seq : public event_task
{
public:
    recv_by_seq(udp& handle, void* buf, size_t& len, const SeqType& seq);
    virtual ~recv_by_seq();
    uint16 peer_type();
    struct sockaddr_in peer_addr_ipv4();
    struct sockaddr_in6 peer_addr_ipv6();
}
  • 注: 该类是udp类的内部public类
  • 注:该类是模板类,其序列号为模板类型(即任意类型),需保证其序列号类型和udp对象绑定seqer的序列号类型一致
  • 构造函数参数分别为udp对象,数据包起点,数据包长度(传入传出参数),序列号
  • 使用该task前必须为udp对象绑定seqer
  • 该task会等待udp对象中的fd可读时接收数据包并获取匹配seq并写到buf中
  • buf参数可以为NULL,内部Buffer接收后将不会拷贝到buf上,可通过udp::internal_buffer函数获取Buffer
  • uint16 peer_type(); 获取对端类型(返回AF_INET/AF_INET6)
  • struct sockaddr_in peer_addr_ipv4(); 获取对端IPv4地址(需确保对端类型为AF_INET)
  • struct sockaddr_in6 peer_addr_ipv6(); 获取对端IPv6地址(需确保对端类型为AF_INET6)

tcp

  • tcp对象有两种类型,因此tcp作为命名空间,其作为tcp命名空间下的类

tcp::listening 监听对象

class listening
{
public:
    listening(int backlog = 64);
    ~listening();
    int bind(const struct sockaddr_in& addr);
    int bind(const struct sockaddr_in6& addr);
}
  • 注: listening类不是task的子类
  • listening对象逻辑上和一个tcp listen fd对应
  • listening(int backlog = 64); 构造函数,backlog为fd挂起队列的最大长度(必须>0)
  • int bind(const struct sockaddr_in& addr); 绑定IPv4地址,返回0成功
  • int bind(const struct sockaddr_in6& addr); 绑定IPv6地址,返回0成功

tcp::connected 连接对象

class connected
{
public:
    connected();
    ~connected();
    template<typename SeqType>
    int bind(size_t min_len, size_t max_len, len_getter* lener, seq_getter* seqer, pkg_seq_unrecv* unrecv = NULL, pkg_seq_failed* failed = NULL);
    template<typename Compare, typename SeqType>
    int bind(size_t min_len, size_t max_len, len_getter* lener, seq_getter* seqer, pkg_seq_unrecv* unrecv = NULL, pkg_seq_failed* failed = NULL);
    uint16 peer_type();
    struct sockaddr_in peer_addr_ipv4();
    struct sockaddr_in6 peer_addr_ipv6();
    unsigned long long count_unrecv() const;
    unsigned long long count_failed() const;
    const void* internal_buffer(size_t& len);
}
  • 注: connected类不是task的子类
  • connected对象逻辑上和一个tcp connect fd对应
  • 使用connected对象通信前必须保证连接建立成功(通过tcp::accepttcp::connect)
  • int bind(size_t min_len, size_t max_len, len_getter* lener, seq_getter* seqer, pkg_seq_unrecv* unrecv, pkg_seq_failed* failed); 绑定单连接异步数据通道模型,返回0成功
  • 使用该函数意味着该连接上通信的数据是乱序的数据包构成的,每个包拥有其独立的seq(将被切割成)
  • min_len 数据包的最小长度(一般是包头长度,其中需要包含表示整个包长度的字段)
  • max_len 数据包的最大产度(主要受限于内存分配)
  • lener 包长度获取回调函数(通过包头获取整个包的长度)
  • seqer 序列号获取回调函数
  • unrecv 序列号未被recv的回调函数
  • failed 序列号获取失败的回调函数
  • 该函数为模板函数,其中序列号的类型为模板类型(即任意类型),另可额外设置序列号类型的比较函数(如bind(...))
  • uint16 peer_type(); 获取对端类型(返回AF_INET/AF_INET6)
  • struct sockaddr_in peer_addr_ipv4(); 获取对端IPv4地址(需确保对端类型为AF_INET)
  • struct sockaddr_in6 peer_addr_ipv6(); 获取对端IPv6地址(需确保对端类型为AF_INET6)
  • unsigned long long count_unrecv() const; 获取当前序列号未被recv的计数
  • unsigned long long count_failed() const; 获取当前获得序列号失败的计数
  • const void* internal_buffer(size_t& len); 返回当前内部Buffer(参数为传出参数,len值会等于Buffer长度)
  • 若connected对象绑定了单连接异步数据通道模型则会使用内部Buffer(该Buffer针对当前connected对象,注意有效期)
  • 使用了内部Buffer时,全部接收的数据包会先放到内部Buffer上,再获取其seq,并路由至对应的事件
  • 若connected对象绑定了单连接异步数据通道模型,收到数据包会进行seq获取匹配并优先被recv_by_seq事件捕获,未被匹配seq的和获取seq失败的数据包将优先被recv事件捕获,剩余的则会触发unrecv或failed回调
  • 接收数据包的优先级为tcp::recv_by_seq事件 > tcp::recv事件 > unrecv/failed回调
  • tcp::recv_till事件其它recv事件不兼容,不能同时使用

tcp 统一返回码

enum {
    success = 0,
    /* -1 ~ -20 basic error */
    unfinished = -1,
    failure = -2, //unknown
    /* -21 ~ -30 accept error */
    address_in_use = -21, //address already in use
    /* -31 ~ -40 connect error */
    /* -41 ~ -60 send error */
    /* -61 ~ -80 recv error */
    packet_length_too_short = -61, //len_getter return length < min_len
    packet_length_too_long = -62 //len_getter return length > max_len
};
  • 以下函数返回码均可在该枚举上查询
  • 返回码有待完善(大多数返回failure)

tcp::accept 接受连接建立请求

class accept : public event_task
{
public:
    accept(int& ret, listening& handle, connected& conn);
    virtual ~accept();
}
  • 构造函数参数分别为返回码,listening对象,connected对象
  • 该task会等待listening对象中的fd可读时让connected对象与对端建立连接(或出错)
  • connected对象必须是连接还未建立的

tcp::connect 发起建立连接请求

class connect : public event_task
{
public:
    connect(int& ret, connected& handle, const struct sockaddr_in& addr);
    connect(int& ret, connected& handle, const struct sockaddr_in6& addr);
    virtual ~connect();
}
  • 构造函数参数分别为返回码,connected对象,目标IPv4/IPv6地址
  • 该task会让connected对象中的fd向目标地址发起连接建立请求,并等待建立成功(或出错)
  • connected对象必须是连接还未建立的
  • 若返回码为失败/错误,那么意味着该connected对象坏掉了,只能析构对象(close fd)了

tcp::send 发送

class send : public event_task
{
public: /* 1~4 bufs */
    send(int& ret, connected& handle, const void* buf0, size_t len0);
    /* 此处省略参数数目为2~4的函数原型 */
    virtual ~send();
}
  • 构造函数参数分别为返回码,connected对象,数据包起点,数据包长度(多个参数版本类似)
  • 该task会等待connected对象中的fd可写时,向连接发送数据
  • 若返回码为失败/错误,那么意味着该connected对象坏掉了,只能析构对象(close fd)了
  • 注意: 该task是不可中断的(详见取消模型)

tcp::recv 接收

class recv : public event_task
{
public:
    recv(int& ret, connected& handle, void* buf, size_t& len);
    virtual ~recv();
}
  • 构造函数参数分别为返回码,connected对象,数据包起点,数据包长度(传入传出参数)
  • 该task会等待connected对象中的fd可读时,读取数据到buf中
  • 若绑定了单连接异步数据通道模型,则buf参数可以为NULL,内部Buffer接收后将不会拷贝到buf上,可通过connected.internal_buffer函数获取Buffer
  • 若返回码为失败/错误,那么意味着该connected对象坏掉了,只能析构对象(close fd)了

tcp::recv_till 接收数据直到...

class recv_till : public event_task
{
public:
    recv_till(int& ret, connected& handle, void* buf, size_t& len); //till fill up buf
    recv_till(int& ret, connected& handle, void* buf, size_t& len, const void* pattern, size_t pattern_len); //till end with pattern
    virtual ~recv_till();
}
  • recv_till(int& ret, connected& handle, void* buf, size_t& len);
  • 接收数据直到填充满buf
  • 参数分别为返回码,connected对象,数据包起点,数据包长度(传入传出参数)
  • recv_till(int& ret, connected& handle, void* buf, size_t& len, const void* pattern, size_t pattern_len);
  • 接收数据直到以模式串结尾(例如HTTP协议包头固定以"\r\n\r\n"结尾)(若buf已经填满还未遇到模式串则返回错误)
  • 参数分别为返回码,connected对象,数据包起点,数据包长度(传入传出参数),模式串地址,模式串长度
  • 该task会等待connected对象中的fd可读时,读取数据直到满足上述条件
  • 该接收模型与其他接收模型不兼容(不能同时用在一个connected对象上)
  • 若返回码为失败/错误,那么意味着该connected对象坏掉了,只能析构对象(close fd)了

tcp::recv_by_seq

template<typename SeqType = uint32>
class recv_by_seq : public event_task
{
public:
    recv_by_seq(int& ret, connected& handle, void* buf, size_t& len, const SeqType& seq);
    virtual ~recv_by_seq();
}
  • 注:该类是模板类,其序列号为模板类型(即任意类型),需保证其序列号类型和connected对象绑定单连接异步数据通道模型的序列号类型一致
  • 构造函数参数分别为返回码,connected对象,数据包起点,数据包长度(传入传出参数),序列号
  • 使用该task前必须为connected对象绑定单连接异步数据通道模型
  • 该task会等待connected对象中的fd可读时,接收数据包切割分段并获取匹配seq并写到buf中
  • buf参数可以为NULL,内部Buffer接收后将不会拷贝到buf上,可通过connected.internal_buffer函数获取Buffer
  • 若返回码为失败/错误,那么意味着该connected对象坏掉了,只能析构对象(close fd)了