Buffer 处理数据输入,是非阻塞Tcp 网络编程中必不可少的东西;
1. Buffer
内部持有vector 保存缓存的数据,readerIndex_ 和 writerIndex_ 作用如上(prependable bytes 初始为8 字节);
retrieve 系列将buffer 中的可读数据提取,只有retrieveAsString 带来返回,其余类似忽略
void retrieveAll() {
_readerIndex = kCheapPrepend;
_writerIndex = kCheapPrepend;
}
std::string retrieveAsString() {
std::string str(peek(), readableBytes());
retrieveAll();
return str;
}
void retrieve(size_t len) {
assert(len <= readableBytes());
_readerIndex += len;
}
void retrieveUntil(const char *end) {
assert(peek() <= end);
assert(end <= beginWrite());
retrieve(end - peek());
}
append 系列为buffer 添加数据
void append(const std::string &str) { append(str.data(), str.length()); }
void append(const char *data, size_t len) {
ensureWriteableBytes(len);
std::copy(data, data + len, beginWrite());
hasWritten(len);
}
void append(const void *data, size_t len) {
append(static_cast<const char *>(data), len);
}
void ensureWriteableBytes(size_t len) {
if (writableBytes() < len) {
makeSpace(len);
}
assert(writableBytes() >= len);
}
void makeSpace(size_t len) {
if (writableBytes() + prependableBytes() < len + kCheapPrepend) {
_buffer.resize(_writerIndex + len);
} else {
assert(kCheapPrepend < _readerIndex);
size_t readable = readableBytes();
std::copy(begin() + _readerIndex, begin() + _writerIndex,
begin() + kCheapPrepend);
_readerIndex = kCheapPrepend;
_writerIndex = _readerIndex + readable;
assert(readable == readableBytes());
}
}
添加数据先转换成char* 合适的格式,确保是否有足够的空间,没有则扩容(当前空余无用空间由prependable 和 writeable 组成若两者加起来不足则vector resize 扩容,而若可以,把readable 移动至最左端)
read 系统调用改成readv(允许单系统读入多个缓冲区),使用scatter / gather IO;
ssize_t Buffer::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;
const ssize_t n = readv(fd, vec, 2);
if (n < 0) {
*savedErrno = errno;
} else if (implicit_cast<size_t>(n) <= writable) {
_writerIndex += n;
} else {
_writerIndex = _buffer.size();
append(extrabuf, n - writable);
}
return n;
}
2. Channel
修改read 事件回调函数和相关设置
typedef std::function<void(Timestamp)> ReadEventCallback;
void handleEvent(Timestamp receiveTime);
void setReadCallback(const ReadEventCallback& cb);
3. TcpConnection
在成员变量中添加Buffer _inputBuffer
修改handleRead 中messageCallback 参数,receiveTime 由poll 提供;
void TcpConnection::handleRead(Timestamp receiveTime) {
int savedErrno = 0;
ssize_t n = _inputBuffer.readFd(_channel->fd(), &savedErrno);
if (n > 0) {
_messageCallback(shared_from_this(), &_inputBuffer, receiveTime);
} else if (n == 0) {
handleClose();
} else {
errno = savedErrno;
LOG_SYSERR << "TcpConnection::handleRead";
handleError();
}
}
Timestamp Poller::poll(int timeoutMs, ChannelList *activeChannels) {
LOG_TRACE << "before sys poll";
int numEvents = ::poll(_pollfds.data(), _pollfds.size(), timeoutMs);
LOG_TRACE << "after sys poll";
Timestamp now(Timestamp::now());
if (numEvents > 0) {
LOG_TRACE << numEvents << " events happened";
fillActiveChannels(numEvents, activeChannels);
} else if (numEvents == 0) {
LOG_TRACE << " nothing happended";
} else {
LOG_SYSERR << "Poller::poll()";
}
return now;
}