网络编程入门08
net模块
Callbacks.h
template<typename T>
inline T* get_pointer(const std::shared_ptr<T>& ptr) //返回shard_ptr的裸指针,感觉意义不大的一个函数
{
return ptr.get();
}
template<typename T>
inline T* get_pointer(const std::unique_ptr<T>& ptr) //返回unique_ptr的裸指针
{
return ptr.get();
}
template<typename To, typename From> //对智能指针进行转换
inline ::std::shared_ptr<To> down_pointer_cast(const ::std::shared_ptr<From>& f) {
if (false)
{
implicit_cast<From*, To*>(0);
}
#ifndef NDEBUG
assert(f == NULL || dynamic_cast<To*>(get_pointer(f)) != NULL);
#endif
return ::std::static_pointer_cast<To>(f);
}
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
typedef std::function<void()> TimerCallback;
typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback; //对于一个含有TcpConnection智能指针的对象座位参数的可调用对象,起不同的别名。 可调用对象,就是一种回调函数
typedef std::function<void (const TcpConnectionPtr&)> CloseCallback;
typedef std::function<void (const TcpConnectionPtr&)> WriteCompleteCallback;
typedef std::function<void (const TcpConnectionPtr&, size_t)> HighWaterMarkCallback;
// the data has been read to (buf, len)
typedef std::function<void (const TcpConnectionPtr&,
Buffer*,
Timestamp)> MessageCallback;
void defaultConnectionCallback(const TcpConnectionPtr& conn);
void defaultMessageCallback(const TcpConnectionPtr& conn,
Buffer* buffer,
Timestamp receiveTime);
Endian.h
linux系统在endian.h头文件中提供了更多的函数进行主机字节和大小端字节序的相互转换,如下:
//在已经知道自己系统的字节序前提下,调用这些函数会更快点
uint16_t htobe16(uint16_t host_16bits);
uint16_t htole16(uint16_t host_16bits);
uint16_t be16toh(uint16_t big_endian_16bits);
uint16_t le16toh(uint16_t little_endian_16bits);
uint32_t htobe32(uint32_t host_32bits);
uint32_t htole32(uint32_t host_32bits);
uint32_t be32toh(uint32_t big_endian_32bits);
uint32_t le32toh(uint32_t little_endian_32bits);
uint64_t htobe64(uint64_t host_64bits);
uint64_t htole64(uint64_t host_64bits);
uint64_t be64toh(uint64_t big_endian_64bits);
uint64_t le64toh(uint64_t little_endian_64bits);
inline uint64_t hostToNetwork64(uint64_t host64) 本地到网络字节序转换
{
return htobe64(host64); //库函数
}
inline uint32_t hostToNetwork32(uint32_t host32)
{
return htobe32(host32);
}
inline uint16_t hostToNetwork16(uint16_t host16)
{
return htobe16(host16);
}
inline uint64_t networkToHost64(uint64_t net64)
{
return be64toh(net64);
}
inline uint32_t networkToHost32(uint32_t net32)
{
return be32toh(net32);
}
inline uint16_t networkToHost16(uint16_t net16)
{
return be16toh(net16);
}
Buffer.h
/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer
///
/// @code
/// +-------------------+------------------+------------------+
/// | prependable bytes | readable bytes | writable bytes |
/// | | (CONTENT) | |
/// +-------------------+------------------+------------------+
/// | | | |
/// 0 <= readerIndex <= writerIndex <= size
calss Buffer{
private:
vector<char> buffer_;
size_t readerIndex_;
size_t writerIndex_;
static const char kCRLF[] = "\r\n"; //在.cc文件里定义的
public:
static const size_t kCheapPrepend = 8;
static const size_t kInitialSize = 1024;
explicit Buffer(size_t initialSize = kInitialSize)
: buffer_(kCheapPrepend + initialSize),
readerIndex_(kCheapPrepend),
writerIndex_(kCheapPrepend)
{
assert(readableBytes() == 0);
assert(writableBytes() == initialSize);
assert(prependableBytes() == kCheapPrepend);
}
void swap(Buffer& rhs);//交换操作 三个变量交换
size_t readableBytes() const;//可以读的数据量
size_t writableBytes() const;//可以写的数据量
size_t prependableBytes() const;//前置数据量
const char* peek() const;//可以读的点
const char* findCRLF() const;//在数据区中搜索KCRLF
{
const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2);
return crlf == beginWrite() ? NULL : crlf;//找到返回字符串点,找不到返回空
}
const char* findEOL() const { //寻找换行符
//C 库函数 void *memchr(const void *str, int c, size_t n) 在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。
const void* eol = memchr(peek(), '\n', readableBytes());
return static_cast<const char*>(eol);
}
const char* findEOL(const char* start) const;//送start处寻找EOL
void retrieve(size_t len)//取数据
void retrieveUntil(const char* end)//从数据头到end取数据
void retrieveInt64(); //就是把读索引前移
void retrieveInt32()
void retrieveInt16()
void retrieveInt8()
void retrieveAll()//取所有数据
string retrieveAllAsString() //取所有数据,返回string
string retrieveAsString(size_t len);//取一部分数据以string返回
StringPiece toStringPiece() const;//数据与stringpiece返回
void append(const char* /*restrict*/ data, size_t len);//写数据
//还有很多写数据的操作
int64_t readInt64() {
int64_t result = peekInt64(); //读Int64_t
retrieveInt64(); //读索引前移
return result;// 返回
}
int64_t peekInt64() const //读8个字节的数据
{
assert(readableBytes() >= sizeof(int64_t));
int64_t be64 = 0;
::memcpy(&be64, peek(), sizeof be64);
return sockets::networkToHost64(be64); //从网络字节序换为本地字节序
}
void prependInt8(int8_t x)//加Int8
{
prepend(&x, sizeof x);
}
void prepend(const void* /*restrict*/ data, size_t len) //往缓冲区前加数据
{
assert(len <= prependableBytes());
readerIndex_ -= len;
const char* d = static_cast<const char*>(data);
std::copy(d, d+len, begin()+readerIndex_);
}
void shrink(size_t reserve); //在保存未读数据的情况下,预留reserve个字节
size_t internalCapacity() const //返回缓冲区的大小
ssize_t readFd(int fd, int* savedErrno) {
char extrabuf[65536];
struct iovec vec[2];
const size_t writable = writableBytes();
vec[0].iov_base = begin()+writerIndex_;
vec[0].iov_len = writable;
vec[1].iov_base = extrabuf;
vec[1].iov_len = sizeof extrabuf;
// when there is enough space in this buffer, don't read into extrabuf.
// when extrabuf is used, we read 128k-1 bytes at most.
const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1;
const ssize_t n = sockets::readv(fd, vec, iovcnt); //readv和writev函数用于在一次函数调用中读、写多个非连续缓冲区。有时也将这两个函数称为散布读(scatter read)和聚集写 (gather write)。
/*
#include <sys/uio.h>
ssize_t readv(int filedes, const struct iovec *iov, int iovcnt); //从一个文件描述符,读数据,可能写在多个缓冲区 从0,1,2,3慢慢写
ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);
两个函数的返回值:若成功则返回已读、写的字节数,若出错则返回-1
*/
if (n < 0)
{
*savedErrno = errno;
}
else if (implicit_cast<size_t>(n) <= writable)
{
writerIndex_ += n;
}
else //如果数据比较小的地区,就需要继续从extrabuf读数据
{
writerIndex_ = buffer_.size();
append(extrabuf, n - writable);
}
return n;
}
}
Timer.h
class Timer{
public:
Timer(TimerCallback cb, Timestamp when, double interval)
: callback_(std::move(cb)),
expiration_(when),
interval_(interval), //间隔启动时间
repeat_(interval > 0.0),
sequence_(s_numCreated_.incrementAndGet()) //每次计时器的序号+1
{ }
void run() const
{
callback_();
}
Timestamp expiration() const { return expiration_; }
bool repeat() const { return repeat_; }
int64_t sequence() const { return sequence_; }
void restart(Timestamp now) {
void Timer::restart(Timestamp now)
{
if (repeat_)
{
expiration_ = addTime(now, interval_);
}
else
{
expiration_ = Timestamp::invalid();
}
}
}
static int64_t numCreated() { return s_numCreated_.get(); }
private:
const TimerCallback callback_; //无参可调用对象
Timestamp expiration_; //过期时间
const double interval_;
const bool repeat_;
const int64_t sequence_;//序号
static AtomicInt64 s_numCreated_;//原子整数
}
TimerId.h 本身就是对Timer的一个包装
class TimerId {
private:
Timer* timer_; //Timer指针
int64_t sequence_; timer的序号
public:
TimerId()
: timer_(NULL),
sequence_(0)
{
}
TimerId(Timer* timer, int64_t seq)
: timer_(timer),
sequence_(seq)
{
}
friend class TimerQueue;
}
TimerQueue.h 定时器队列
*timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景。*
一,相关操作函数
#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags) ;
/*
它是用来创建一个定时器描述符timerfd
第一个参数:clockid指定时间类型,有两个值:
CLOCK_REALTIME :Systemwide realtime clock. 系统范围内的实时时钟
CLOCK_MONOTONIC:以固定的速率运行,从不进行调整和复位 ,它不受任何系统time-of-day时钟修改的影响
第二个参数:flags可以是0或者O_CLOEXEC/O_NONBLOCK。
返回值:timerfd(文件描述符)
*/
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);
struct itimerspec
{
struct timespec it_interval; //首次超时后,每隔it_interval超时一次
struct timespec it_value; //首次超时时间
}
typedef long time_t;
#ifndef _TIMESPEC
#define _TIMESPEC
struct timespec {
time_t tv_sec; // seconds
long tv_nsec; // and nanoseconds
};
#endif
struct timespec有两个成员,一个是秒,一个是纳秒, 所以最高精确度是纳秒。
一般由函数int clock_gettime(clockid_t, struct timespec *)获取特定时钟的时间,常用如下4种时钟:
CLOCK_REALTIME 统当前时间,从1970年1.1日算起
CLOCK_MONOTONIC 系统的启动时间,不能被设置
CLOCK_PROCESS_CPUTIME_ID 本进程运行时间
CLOCK_THREAD_CPUTIME_ID 本线程运行时间
int createTimerfd()
{
int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
TFD_NONBLOCK | TFD_CLOEXEC);
if (timerfd < 0)
{
LOG_SYSFATAL << "Failed in timerfd_create";
}
return timerfd;
}
struct timespec howMuchTimeFromNow(Timestamp when)
{
int64_t microseconds = when.microSecondsSinceEpoch()
- Timestamp::now().microSecondsSinceEpoch();
if (microseconds < 100)
{
microseconds = 100;
}
struct timespec ts;
ts.tv_sec = static_cast<time_t>(
microseconds / Timestamp::kMicroSecondsPerSecond);
ts.tv_nsec = static_cast<long>(
(microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
return ts;
}
void readTimerfd(int timerfd, Timestamp now)
{
uint64_t howmany;
ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
if (n != sizeof howmany)
{
LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
}
}
/*
int timerfd_settime(int tfd, int flags, const struct itimerspec *newValue, struct itimerspec *oldValue)
功能: 用于启动或关闭指定fd的定时器。
tfd: timerfd,由timerfd_create函数返回。
flags: 1表示设置的是绝对时间;0表示相对时间。
newValue: 指定新的超时时间,若newValue.it_value非0则启动定时器,否则关闭定时器。若newValue.it_interval为0则定时器只定时一次,否则之后每隔设定时间超时一次。
oldValue:不为NULL时则返回定时器这次设置之前的超时时间。
return:失败则返回-1。
*/
void resetTimerfd(int timerfd, Timestamp expiration)
{
// wake up loop by timerfd_settime()
struct itimerspec newValue;
struct itimerspec oldValue;
memZero(&newValue, sizeof newValue);
memZero(&oldValue, sizeof oldValue);
newValue.it_value = howMuchTimeFromNow(expiration);
int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
if (ret)
{
LOG_SYSERR << "timerfd_settime()";
}
}
calss TimerQueue {
private:
typedef std::pair<Timestamp, Timer*> Entry; //时间戳和定时器设为一个pair 命名入口
typedef std::set<Entry> TimerList; //红黑树实现的一个入口序列
typedef std::pair<Timer*, int64_t> ActiveTimer; //Timer指针和Int64_t定义为活跃 定时器
typedef std::set<ActiveTimer> ActiveTimerSet; //活跃定时器列表
EventLoop* loop_;
const int timerfd_;
Channel timerfdChannel_;
// Timer list sorted by expiration
TimerList timers_;
// for cancel()
ActiveTimerSet activeTimers_;
bool callingExpiredTimers_; /* atomic */
ActiveTimerSet cancelingTimers_;
public:
explicit TimerQueue(EventLoop* loop)
: loop_(loop),
timerfd_(createTimerfd()),
timerfdChannel_(loop, timerfd_), //channel里一个循环事件指针,一个文件描述符
timers_(), //时间戳 + 定时器指针组成的Pair
callingExpiredTimers_(false)
{
timerfdChannel_.setReadCallback( //绑定回调函数
std::bind(&TimerQueue::handleRead, this));
// we are always reading the timerfd, we disarm it with timerfd_settime.
timerfdChannel_.enableReading(); //允许读数据 表明这个频道加入了一个事件循环对象
}
~TimerQueue() {
timerfdChannel_.disableAll();
timerfdChannel_.remove(); //从事件循环中删除这个频道
::close(timerfd_);
// do not remove channel, since we're in EventLoop::dtor();
for (const Entry& timer : timers_) //删掉每一个di定时器ng
{
delete timer.second;
}
}
TimerId addTimer(TimerCallback cb,
Timestamp when,
double interval)
{
Timer* timer = new Timer(std::move(cb), when, interval); //创建一个定时器
loop_->runInLoop(
std::bind(&TimerQueue::addTimerInLoop, this, timer)); //绑定得是addTimerInLoop这个成员函数,参数为timer指针
return TimerId(timer, timer->sequence());
}
void cancel(TimerId timerId)
{
loop_->runInLoop(
std::bind(&TimerQueue::cancelInLoop, this, timerId)); //新的可调用对象,绑定cancelInLoop函数,参数为timerId
}
void addTimerInLoop(Timer* timer)
{
loop_->assertInLoopThread();
bool earliestChanged = insert(timer);
if (earliestChanged) //如果新插入的定时器最早过时,说明最先出发事件的一定是它
{
resetTimerfd(timerfd_, timer->expiration()); //把这个时间队列里,过期时间更新,更新为最新的最小值,也就是说这个fd关注的永远是最先过期的事件
}
}
void cancelInLoop(TimerId timerId);
{
loop_->assertInLoopThread();
assert(timers_.size() == activeTimers_.size());
ActiveTimer timer(timerId.timer_, timerId.sequence_); //指针 + 序号 构造一个activetimer对象
ActiveTimerSet::iterator it = activeTimers_.find(timer); //在actimeTimer里找
if (it != activeTimers_.end())
{
size_t n = timers_.erase(Entry(it->first->expiration(), it->first)); //时间戳 + 定时器指针, 清除
assert(n == 1); (void)n;
delete it->first; // FIXME: no delete please //删除这个定时器
activeTimers_.erase(it); //删除这个 指针+ 序号 在actime set 里对象
}
else if (callingExpiredTimers_)
{
cancelingTimers_.insert(timer); //加入删除的定时器列表里
}
assert(timers_.size() == activeTimers_.size());
}
// called when timerfd alarms
void handleRead()
{
loop_->assertInLoopThread();
Timestamp now(Timestamp::now());
readTimerfd(timerfd_, now);
std::vector<Entry> expired = getExpired(now); //得到所有过期的定时器 返回列表 时间戳+定时器指针
callingExpiredTimers_ = true;
cancelingTimers_.clear();
// safe to callback outside critical section
for (const Entry& it : expired) //所有到时间的定时器
{
it.second->run(); //调用timer->run() 直接调用定时器当时绑定的回调函数
}
callingExpiredTimers_ = false;
reset(expired, now);
}
// move out all expired timers
std::vector<Entry> getExpired(Timestamp now)
{
assert(timers_.size() == activeTimers_.size());
std::vector<Entry> expired;
Entry sentry(now, reinterpret_cast<Timer*>(UINTPTR_MAX));
TimerList::iterator end = timers_.lower_bound(sentry);
assert(end == timers_.end() || now < end->first);
std::copy(timers_.begin(), end, back_inserter(expired)); //第一个定时器到end之前的最后一个,插入expried
timers_.erase(timers_.begin(), end); //时间戳+指针里的 set
for (const Entry& it : expired)
{
ActiveTimer timer(it.second, it.second->sequence()); //删除 指针 + seq里的数据
size_t n = activeTimers_.erase(timer);
assert(n == 1); (void)n;
}
assert(timers_.size() == activeTimers_.size());
return expired; //返回被删除的数组, 时间戳 + 指针
}
void reset(const std::vector<Entry>& expired, Timestamp now)
{
Timestamp nextExpire;
for (const Entry& it : expired)
{
ActiveTimer timer(it.second, it.second->sequence());
if (it.second->repeat() //如果是一个周期任务,计算并且不再取消列表里
&& cancelingTimers_.find(timer) == cancelingTimers_.end())
{
it.second->restart(now);
insert(it.second);
}
else
{
// FIXME move to a free list
delete it.second; // FIXME: no delete please 如果单词任务,删除定时器
}
}
bool insert(Timer* timer)
{
loop_->assertInLoopThread();
assert(timers_.size() == activeTimers_.size());
bool earliestChanged = false;
Timestamp when = timer->expiration(); //这个定时器的过期时间
TimerList::iterator it = timers_.begin();
if (it == timers_.end() || when < it->first) //如果当前定时器最先到期
{
earliestChanged = true; //最早定时器标记设为TRUE
}
{
std::pair<TimerList::iterator, bool> result
= timers_.insert(Entry(when, timer)); //先插入list
assert(result.second); (void)result;
}
{
std::pair<ActiveTimerSet::iterator, bool> result
= activeTimers_.insert(ActiveTimer(timer, timer->sequence())); //定时器指针与序号
assert(result.second); (void)result;
}
assert(timers_.size() == activeTimers_.size());
return earliestChanged;
}
}