TCP网络编程最本质的是处理三个半事件

1、连接建立:服务器accept(被动)接受连接,客户端connect(主动)发起连接。

2、连接断开:主动断开(close、shutdown),被动断开(read返回0)。

3、消息到达:文件描述符可读。

4、消息发送完毕:这算半个。对于低流量的服务,可不必关心这个事件,这里的发送完毕是指数据写入操作系统缓冲区,将由TCP协议栈负责数据的发送与重传,不代表对方已经接收到数据。对于高流量的程序,应用要在发送完毕后再发送,以免数据丢包。

一个套接字有两个缓冲区,一个接收缓冲区一个发送缓冲区,当一个套接字到来的时候先被内核缓冲区接收

接下来看muduo 对这三个半事件的封装

通过TcpServer 提供了三个成员函数来注册三个回调函数,连接成功和断开用了一个回调函数。

Echo 服务示例:

#include "examples/simple/echo/echo.h"#include "muduo/base/Logging.h"
#include "muduo/net/EventLoop.h"#include <unistd.h>// using namespace muduo;
// using namespace muduo::net;int main()
{LOG_INFO << "pid = " << getpid();muduo::net::EventLoop loop;muduo::net::InetAddress listenAddr(2007);EchoServer server(&loop, listenAddr);server.start();loop.loop();
}
#ifndef MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H
#define MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H#include "muduo/net/TcpServer.h"// RFC 862
class EchoServer
{public:EchoServer(muduo::net::EventLoop* loop,const muduo::net::InetAddress& listenAddr);void start();  // calls server_.start();private:void onConnection(const muduo::net::TcpConnectionPtr& conn);void onMessage(const muduo::net::TcpConnectionPtr& conn,muduo::net::Buffer* buf,muduo::Timestamp time);muduo::net::TcpServer server_;
};#endif  // MUDUO_EXAMPLES_SIMPLE_ECHO_ECHO_H
#include "examples/simple/echo/echo.h"#include "muduo/base/Logging.h"using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;// using namespace muduo;
// using namespace muduo::net;EchoServer::EchoServer(muduo::net::EventLoop* loop,const muduo::net::InetAddress& listenAddr): server_(loop, listenAddr, "EchoServer")
{server_.setConnectionCallback(std::bind(&EchoServer::onConnection, this, _1));server_.setMessageCallback(std::bind(&EchoServer::onMessage, this, _1, _2, _3));
}void EchoServer::start()
{server_.start();
}void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
{LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "<< conn->localAddress().toIpPort() << " is "<< (conn->connected() ? "UP" : "DOWN");
}void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn,muduo::net::Buffer* buf,muduo::Timestamp time)
{muduo::string msg(buf->retrieveAllAsString());LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, "<< "data received at " << time.toString();conn->send(msg);
}

EventLoop的封装

one loop  per thread意思是说每个线程最多只能有一个EventLoop对象。

EventLoop对象构造的时候,会检查当前线程是否已经创建了其他EventLoop对象,如果已创建,终止程序(LOG_FATAL)

EventLoop构造函数会记住本对象所属线程(threadId_)。

创建了EventLoop对象的线程称为IO线程,其功能是运行事件循环(EventLoop::loop)

#ifndef MUDUO_NET_EVENTLOOP_H
#define MUDUO_NET_EVENTLOOP_H#include <boost/noncopyable.hpp>#include <muduo/base/CurrentThread.h>
#include <muduo/base/Thread.h>namespace muduo
{
namespace net
{///
/// Reactor, at most one per thread.
///
/// This is an interface class, so don't expose too much details.
class EventLoop : boost::noncopyable
{public:EventLoop();~EventLoop();  // force out-line dtor, for scoped_ptr members.////// Loops forever.////// Must be called in the same thread as creation of the object.///void loop();void assertInLoopThread(){if (!isInLoopThread()){abortNotInLoopThread();}}bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }static EventLoop* getEventLoopOfCurrentThread();private:void abortNotInLoopThread();bool looping_; /* atomic */const pid_t threadId_;     // 当前对象所属线程ID
};}
}
#endif  // MUDUO_NET_EVENTLOOP_H
#include <muduo/net/EventLoop.h>#include <muduo/base/Logging.h>#include <poll.h>using namespace muduo;
using namespace muduo::net;namespace
{
// 当前线程EventLoop对象指针
// 线程局部存储
__thread EventLoop* t_loopInThisThread = 0;
}EventLoop* EventLoop::getEventLoopOfCurrentThread()
{return t_loopInThisThread;
}EventLoop::EventLoop(): looping_(false),threadId_(CurrentThread::tid())
{LOG_TRACE << "EventLoop created " << this << " in thread " << threadId_;// 如果当前线程已经创建了EventLoop对象,终止(LOG_FATAL)if (t_loopInThisThread){LOG_FATAL << "Another EventLoop " << t_loopInThisThread<< " exists in this thread " << threadId_;}else{t_loopInThisThread = this;}
}EventLoop::~EventLoop()
{t_loopInThisThread = NULL;
}// 事件循环,该函数不能跨线程调用
// 只能在创建该对象的线程中调用
void EventLoop::loop()
{assert(!looping_);// 断言当前处于创建该对象的线程中assertInLoopThread();looping_ = true;LOG_TRACE << "EventLoop " << this << " start looping";::poll(NULL, 0, 5*1000);LOG_TRACE << "EventLoop " << this << " stop looping";looping_ = false;
}void EventLoop::abortNotInLoopThread()
{LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this<< " was created in threadId_ = " << threadId_<< ", current thread id = " <<  CurrentThread::tid();
}

muduo库net源码分析一(网络编程本质)相关推荐

  1. muduo库net源码分析六(Socket 封装)

    Endian.h 封装了字节序转换函数(全局函数,位于muduo::net::sockets名称空间中). #ifndef MUDUO_NET_ENDIAN_H #define MUDUO_NET_E ...

  2. 第三季2:ORTP库的源码分析、RTP发送实验的源码分析

    以下内容源于朱有鹏课程,如有侵权,请告知删除. 一.ORTP库源码分析 1.ORTP库概览 (1)库提供一堆功能函数(本身没有main),都在src目录下 (2)库的使用给了案例(有main),在sr ...

  3. PhxPaxos源码分析:网络

    2019独角兽企业重金招聘Python工程师标准>>> 欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:LBD 了解分布式系统的童鞋肯定听过Paxos算法的大名.Pa ...

  4. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  5. 飞鸽传书源码分析三-网络

    转载请注明出处:http://blog.csdn.net/mxway/article/details/44195099 本文是在飞鸽传书2.06源码基础之上进行分析的. 一.网络的初始化 飞鸽传书主窗 ...

  6. 2个关于Adapter库的源码分析(AdapterDelegate、BaseRecyclerViewHelper)

    0x00 概述 核心思想:都是围绕如何解决viewType.视图.数据与视图的绑定来进行一系列的封装,不同的库有着自己不同的手段而已 Adapter能在数据变化时候,内部实现逻辑不会改变,仅在外部添加 ...

  7. 在ADSP21489上使用FFT和IFFT库完整源码--分析窗为矩形窗

    时隔8年再次重新在21489上重新整理此功能,这次是完整的源码,重新把工程书写了搭建了一遍 再次编辑又有新的心得,学到了当初不曾了解全面的知识点 1.ifft后对信号的重建问题 2.调试出错问题 /* ...

  8. android网络编程终结者,小七论坛终结者V2.0升级版源码 - 源码下载|Internet/网络编程|远程控制编程|源代码 - 源码中国...

    文件名大小更新时间 小七论坛终结者V2.0升级版源码\Bin\Assist.dll409602018-05-16 小七论坛终结者V2.0升级版源码\Bin\bk.gif12232018-05-16 小 ...

  9. 2022最新中高级Android面试题目,网络相关+Android三方库的源码分析+数据结构与算法

    前言 最近有些朋友提问,Android QQ空间 换肤实现原理是什么?于是,我决定在这里做一下回答.对这个方面感兴趣的朋友也可以来看下. 手q的换肤机制主要是通过拦截系统resource中的sPrel ...

  10. 文件解析库doctotext源码分析

    doctotext中没有make install选项,make后生成可执行文件 在buile目录下面有.so动态库和头文件,需要的可以从这里面拷贝 build/doctotext就是可执行程序. do ...

最新文章

  1. OVS DPDK--Ring端口配置(五)
  2. Mysql在大型网站的应用架构演变
  3. C++ 定时器的用法:SetTimer和Ontimer
  4. 浅谈 js 正则字面量 与 new RegExp 执行效率
  5. 目前最完整的前端框架 Vue.js 全面介绍
  6. AudioSession property 详解及使用方法,包括检测是否有声音正在运行,音量更改等。...
  7. Axure 网站后台-能源管理系统 rp 9原模板代码下载
  8. vivado查看原理图
  9. mac下使用php cURL方法nginx502错误
  10. 相关性分析热点图_防老剂TMQ及6PPD价格上涨逻辑分析及后市展望
  11. 深度学习模型评价标准
  12. 流媒体技术笔记(视频编码相关)
  13. gsoc 任务_我在GSoC'20中进行编码的第三周
  14. 四级英语作文:拯救动物
  15. Committer 蔡正昕专访:勇敢迈出第一步,做开源没有那么难
  16. 【更新】Project 读写管理控件Aspose.Tasks V17.5发布 | 附下载
  17. 图片上传失败了?憋慌,有可能不是Bug哦~
  18. OpenMV4驱动mg995舵机
  19. 易语言教程数据库置数据库密码
  20. am4针脚定义_AMD新一代处理器改用AM4插槽:针脚数提升40%,140W供电!

热门文章

  1. “智慧零售”下的信息化会员营销
  2. Fliqlo:一款精致高逼格的翻页时钟屏保软件
  3. ENVI操作:监督分类
  4. 嵌入式系统笔记之声音
  5. python在线评测系统_怎样做一个 Online Judge(在线评测系统)?
  6. 智慧产业园区综合解决方案
  7. 考研,我就推荐几个常用的APP
  8. RPLIDAR在ROS下快速上手教程
  9. 组卷积和深度可分离卷积
  10. 微信小程序 组件传值(二) triggerEvent 子传父