-
Notifications
You must be signed in to change notification settings - Fork 11
事件API
chishaxie edited this page Jan 5, 2014
·
9 revisions
- 以下全部内容均在ccf命名空间中
- 事件API又称功能API,事件API越丰富也意味着功能越丰富
- 一般情况,事件API应该和await、all_of、any_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)
)
)
class sleep : public event_task
{
public:
sleep(uint64 timeout); //ms
virtual ~sleep();
}
-
sleep(uint64 timeout);
参数为休息的毫秒数 - 该task在会等待timeout毫秒,timeout毫秒后则执行完毕
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)
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回调
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是不可中断的(详见取消模型)
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)
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命名空间下的类
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成功
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::accept或tcp::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事件不兼容,不能同时使用
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)
class accept : public event_task
{
public:
accept(int& ret, listening& handle, connected& conn);
virtual ~accept();
}
- 构造函数参数分别为返回码,listening对象,connected对象
- 该task会等待listening对象中的fd可读时让connected对象与对端建立连接(或出错)
- connected对象必须是连接还未建立的
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)了
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是不可中断的(详见取消模型)
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)了
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)了
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)了