程序员

muduo源码分析——TCPConnection

作者:admin 2021-07-01 我要评论

这里简要分析TCPConnection的用法以及代码 1. TcpConnection 发送 2. TcpConnection 接收 TcpConnection::handleRead调用 ssize_t n inputBuffer_.readFd(channe...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

这里简要分析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://blog.csdn.net/weixin_44537992/article/details/114639584

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • muduo源码分析——TCPConnection

    muduo源码分析——TCPConnection

  • 数论之因子和与因子个数

    数论之因子和与因子个数

  • 今年底出版《算法竞赛》,这是大纲

    今年底出版《算法竞赛》,这是大纲

  • 宿舍员工组网

    宿舍员工组网

腾讯云代理商
海外云服务器