skylu网络库

主要参考sylar和handy的实现

时间戳

2020-4-25

快速浏览一遍github上其他人的网络库实现,挑选出比较适合自己的来进行参考。其中将sylar 的日志模块和配置模块删去一些冗余复杂的内容之后作为自己的日志模块和配置模块。sylar 看了好久他的这两个模块,写的太好了,学到了很多东西,不用实在对不起自己前段时间的学习。

2020-4-26

完成内容

封装锁、线程池、网络地址、文件管理类等模块。

线程类没有使用c++11的线程,而是用自己封装的Thread类,里面包含锁。通过再构造函数中使用信号量来实现当系统创建完线程后构造函数才会退出。(简单来说就是在构造函数中放一个信号量等待,当线程创建完后发送信号量)

线程池使用安全队列存放task,线程在创建的时候阻塞等待队列不为空的情况。

网络地址抽象了一个地址类,目前只实现了ipv4的地址。

文件管理类主要管理文件句柄,使用单例模式。一般来说,从文件管理类中获取所需要的文件句柄(socket)来进行设置是否阻塞、阻塞IO的超时时间.

后续可以的优化:

[ ]线程池可以参考之前实现的线程池、java线程池来完善扩容、缩容
[ ]网络地址中可以加个广播、IPv6地址,更好的兼容不同机器(字节序)

Next Day

[*]完成TCP 部分的网络库。能够通过简单几行代码Echo回射服务器。
[]Epoll部分的封装和事件派发

2020-4-27

完成内容

socket相关部分的封装,支持IPv4地址的TCP\UDP。

抽象出address 地址来实现具体的IPv4Address地址类,主要存放sockaddr_in成员。

socket相关操作封装(包括socket设置)。通过简单的静态函数createTCP\UDP创建相关socket。之后根据socket类型依次调用相关API。

Next Day

[]Epoll部分的封装
[]事件派发器
[]缓冲区设计
[]TCP连接类

2020-4-30

学习内容

  • 智能指针和锁
    在析构函数中加锁的时候需要考虑竞态情况下,例如一个线程中的对象正在析构,另一个线程中却在这个对象的成员函数中,同时两个函数都需要加对方所持有的锁。

  • 没有通过具体的数据实验,不能片面的认为读写锁效率比互斥锁高,实际上互斥锁的效率更高一些。可以通过shared_ptr中的引用次数来实现读写锁的功能,同时实现copy-on-write。

    void read()
    {
      {
           Lock()
           shared_ptr<Type> val = g_ptr;
      }
       ....
    }
    
    void write()
    {
    	Lock()
    	shared_ptr<Type> val;
    	if(!g_ptr.unique())
    	{
    		val.reset(new Type(*g_ptr));	
    		g_ptr =val;
    	}
    	....
    	
    }
    
    
  • 服务器常用模型

    • 单线程服务器常用模型Reactor : 非阻塞IO + IO复用(one loop event)
    • 多线程服务器常用模型:非阻塞IO+one loop(Reactor) per thread

多线程模型并不能增加并发连接数提升,在32位操作系统下,用户内存空间位3G,假设一个线程的栈空间需要10M,那么最多也就只能并发出300个连接。事实上应该是在每个线程中复用IO,同时监听多条连接,这几个也就是IO线程,然后把计算密集操作放到线程池中执行。
同时对于计算密集的服务多线程也不能提高吞吐量,但是可以降低服务响应延迟。

最重要的一点,线程池大小的阻抗匹配原则,也就是线程池一般来说应该多大。T=C/P(T就是数量,C是分配给该任务的CPU数,P是密集计算所占线程执行的总时间比)。其中当P<0.2的时候 不适用,T可以取固定值。由于这个计算并不是准确的,可以根据实际情况上下浮动50%.

心得

不得不说,陈硕的linux多线程服务器编程真是一本好书,将很多之前零零散散用的知识都归纳起来,有了一个更深的理解。相比之前仅仅通过看博客,好的书籍一方面可以学到更多的知识,另一方面也是在整理自己的知识体系,不至于分崩离析。