這里簡要分析TCPConnection的用法以及代碼
1. TcpConnection 發送

2. TcpConnection 接收
TcpConnection::handleRead呼叫
ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);
一次把內核緩沖區的資料讀完

3 TcpConnection 一些小點
3.1 TcpConnection 接收設計原理
TCP協議的shutdown與close等描述
上個文章解釋了為什么muduo的TCP連接中,使用shutdown后呼叫read() == 0來判斷對端是否關閉寫,因為發送FIN之后,接收方會read回傳0,非阻塞read沒有資料回傳-1,


這里有一點需要注意,socket::shutdown()本身只會關閉連接,不會關閉socket fd,TCPConnection有一個 組合的socket物件,std::unique_ptr< Socket> socket_;而socket物件RAII的解構式中有 sockets::close(sockfd_);

3.2 TcpConnection 存盤變數
TcpConnection 中,可以使用使用boost::any與boost::any_cast實作任意型別的資料存盤與提取,muduo中例子實作對conn中的FILE*指標的存盤與操作
boost::any相關使用分析
boost::any context_;
void setContext(const boost::any& context)
{ context_ = context; }
const boost::any& getContext() const
{ return context_; }

注意問題


3.3 TcpConnection 中一個簡單的shared_ptr
這是muduo的一個簡單的tcp連接,但是通過shared_ptr來管理FILE*的生命周期,使其運用了C++的RAII,生命周期與TCPConnection一致,同時節省了很多代碼,
#include "muduo/base/Logging.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
#include <stdio.h>
#include <unistd.h>
using namespace muduo;
using namespace muduo::net;
void onHighWaterMark(const TcpConnectionPtr& conn, size_t len)
{
LOG_INFO << "HighWaterMark " << len;
}
const int kBufSize = 64*1024;
const char* g_file = NULL;
typedef std::shared_ptr<FILE> FilePtr; //line3
void onConnection(const TcpConnectionPtr& conn)
{
LOG_INFO << "FileServer - " << conn->peerAddress().toIpPort() << " -> "
<< conn->localAddress().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");
if (conn->connected())
{
LOG_INFO << "FileServer - Sending file " << g_file
<< " to " << conn->peerAddress().toIpPort();
conn->setHighWaterMarkCallback(onHighWaterMark, kBufSize+1);
FILE* fp = ::fopen(g_file, "rb"); // line1
if (fp)
{
FilePtr ctx(fp, ::fclose); //line2
conn->setContext(ctx);
char buf[kBufSize];
size_t nread = ::fread(buf, 1, sizeof buf, fp);
conn->send(buf, static_cast<int>(nread));
}
else
{
conn->shutdown();
LOG_INFO << "FileServer - no such file";
}
}
}
void onWriteComplete(const TcpConnectionPtr& conn)
{
const FilePtr& fp = boost::any_cast<const FilePtr&>(conn->getContext());
char buf[kBufSize];
size_t nread = ::fread(buf, 1, sizeof buf, get_pointer(fp));
if (nread > 0)
{
conn->send(buf, static_cast<int>(nread));
}
else
{
conn->shutdown();
LOG_INFO << "FileServer - done";
}
}
int main(int argc, char* argv[])
{
LOG_INFO << "pid = " << getpid();
if (argc > 1)
{
g_file = argv[1];
EventLoop loop;
InetAddress listenAddr(2021);
TcpServer server(&loop, listenAddr, "FileServer");
server.setConnectionCallback(onConnection);
server.setWriteCompleteCallback(onWriteComplete);
server.start();
loop.loop();
}
else
{
fprintf(stderr, "Usage: %s file_for_downloading\n", argv[0]);
}
}
如果不用shared_ptr,則如下
void onConnection(const TcpConnectionPtr& conn)
if...
else
{
if (!conn->getContext().empty())
{
FILE* fp = boost::any_cast<FILE*>(conn->getContext());
if (fp)
{
::fclose(fp);
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/275888.html
標籤:其他
下一篇:數論之因子和與因子個數

