1. SIGPIPE
SIGPIPE 默认行为是终止进程,在命令行程序中是合理的,但在网络编程中,这意味着如果对方断开连接而本地继续写入的话,会造成服务进程意外退出;
解决方法是在程序开始时忽略SIGPIPE;
class IgnoreSigPipe {
public:
IgnoreSigPipe() {
::signal(SIGPIPE, SIG_IGN);
}
};
IgnoreSigPipe initObj;
2. TcpNoDelay
此功能禁用Nagle 算法,避免连续发包出现延迟;
TcpConnection.h
+ void setTcpNoDelay();
底层实现:
::setsockopt(_sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof optval);
3. 高低水平回调
高水平回调用于发送数据高于对方接受数据造成本地堆积,低水平回调用于本地处理数据过快造成等待发送数据;
两者类似PWM,前者可以通过回调停止读取数据,后者可以在回调中恢复相应的读取功能;
在发送时读取buffer 中的数据若无可调用低水平回调(writeCompleteCallback)
void TcpConnection::sendInLoop(const std::string &message) {
_loop->assertInLoopThread();
ssize_t nwrote = 0;
if (!_channel->isWriting() && _outputBuffer.readableBytes() == 0) {
nwrote = ::write(_channel->fd(), message.data(), message.size());
if (nwrote >= 0) {
if (implicit_cast<size_t>(nwrote) < message.size()) {
LOG_TRACE << "I am going to write more data";
+ } else if (_writeCompleteCallback) {
+ _loop->queueInLoop(
std::bind(_writeCompleteCallback, shared_from_this()));
}
} else {
nwrote = 0;
if (errno != EWOULDBLOCK) {
LOG_SYSERR << "TcpConnection::sendInLoop";
}
}
}
assert(nwrote >= 0);
if (implicit_cast<size_t>(nwrote) < message.size()) {
_outputBuffer.append(message.data() + nwrote, message.size() - nwrote);
if (!_channel->isWriting()) {
_channel->enableWriting();
}
}
}
void TcpConnection::handleWrite() {
_loop->assertInLoopThread();
if (_channel->isWriting()) {
ssize_t n = ::write(_channel->fd(), _outputBuffer.peek(),
_outputBuffer.readableBytes());
if (n > 0) {
_outputBuffer.retrieve(n);
if (_outputBuffer.readableBytes() == 0) {
_channel->disableWriting();
+ if (_writeCompleteCallback) {
+ _loop->queueInLoop(
std::bind(_writeCompleteCallback, shared_from_this()));
}
if (_state == kDisconnecting) {
shutdownInLoop();
}
} else {
LOG_TRACE << "I am going to write more data";
}
} else {
LOG_SYSERR << "TcpConnection::handleWrite";
}
} else {
LOG_TRACE << "Connection is down, no more writing";
}
}