5大I/O模型介绍 阻塞式I/O模型 非阻塞式I/O模型 I/O复用模型 异步I/O 阻塞式I/O 未完成输入或者输出,导致程序阻塞,直到输入输出工作完成为止。在网络编程中,进程读取套接字关联的内核缓冲区数据,当缓冲区为空时,不会再进行系统调用,而是被投入到睡眠状态,但是等到内核缓冲区有数据后,进程又开始读取数据;当从进程往套接字缓冲区写数据时,缓冲区中没有多余空间来容纳数据,进程就被投入睡眠,等待用户读取缓冲区中的数据空出空间。然后唤醒进程进行写操作;当要求读取一定长度的数据时,而每次缓冲区中数据的长度不符合要求长度,进程也会陷入等待,直到数据满足读取期望为止。 以上是出自书上的一幅图,没有包含写数据的哪一部分。 非阻塞I/O 相对于阻塞I/O,非阻塞I/O是就算你套接字关联内核空间没有数据可读,他还是要不停地进行系统调用,判断是否有数据可读,当有数据时就会将内核数据复制到进程中,作相应处理,写数据是同样的道理。所以不难看出,非阻塞相比于阻塞多了频繁的系统调用,所以会消耗系统 继续阅读 >>


畅柯 18/12/23 15:32:03
详解哈希表(上)什么是哈希表不可逆性“碰撞”现象如何构造一个哈希算法:构造哈希函数的方法处理冲突的方法: Hi~ o( ̄▽ ̄)ブ 本篇博客分为上下两部分,上半部分主要讲解哈希表的基础知识,下半部分主要是功能代码实现。 φ(≧ω≦*)♪ 什么是哈希表 哈希,就是把任意长度的输入通过散列算法变换成固定长度的输出。 哈希表,是根据关键码值(Key value)而直接进行访问的数据结构。 通俗理解的说,就是通过一个函数算法,把需要存储的东西经过这个算法转化成一个更简单的东西(关键码值),然后将这个关键码值作为所存储东西的地址,直接通过地址进行查找,简化了查找算法。 给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。 既然哈希表的核心,就是一个函数,那么,我们就可以通过研究函数的性质来研究哈希表。 ︿( ̄︶ ̄)︿ 不可逆性 首先来看一个简单的函数: f(key)=a 继续阅读 >>


赖鑫 18/12/21 01:00:04
协程实现原理 协程的本质都是通过修改 ESP 和 EIP 指针来实现的。其理论上还是单线程在运行. 程序在CPU上运行时依赖3个寄存器: ESP寄存值指向当前栈顶地址,指向当前指令需要的数据 EBP指向当前活动栈帧的基地址 指令寄存器IP,指向当前需要运行的指令 其中主要有(IP,ESP)寄存器最重要,这两个寄存器指针的改变可以修改当前需要加载到 CPU 运行的指令和数据,当某个操作陷入到耗时的等待中时,通过修改这两个指针即可让出CPU,交给其他的任务去使用,每个任务都必须主动的让出CPU,然后等待下一次的调度来继续未完成的任务,这样就可以最大程度的利用CPU,当一个任务等待过程非常短的时候,就出现了多个任务并行运行的效果,也就是协程。 实现协程的多种方法 利用 glibc 的 ucontext 组件(云风的库) 使用汇编来切换上下文(实现miniC协程,腾讯libco) 利用C语言语法switch-case的奇淫技巧来实现(Protothreads) 利用了 C 语言的 setjmp 和 lon 继续阅读 >>


刘生玺 18/12/20 22:56:00
文章目录前言一、创建DESUtil工具类二、创建EncryptPropertyPlaceholderConfigurer类三、修改spring-dao.xml的相关配置 前言 我们常常在写数据库配置文件jdbc.properties的时候,都是以明文方式来显示,这样做其实是很不安全的,万一被黑客爬取到这些信息连接上数据库,造成数据泄露是很危险的。所以,我们想到对明文进行加密,使用密文来显示是个不错的方法~ 加密一般分为可逆加密和不可逆加密,其中可逆加密一般又分为对称加密和非对称加密,对称加密是使用了同样的密钥进行加密解密,而非对称加密则是使用公钥加密之后必须使用私钥来解密。不可逆加密之后是无法解密的。DES加密就是一种对称加密。 现阶段先不研究加密算法,主要看看在Java中如何使用DES进行加密和解密的~ 一、创建DESUtil工具类 package com.yaya.o2o.util.jdbcpwddes; import sun.misc.BASE64Decoder; import sun.misc 继续阅读 >>


贺含悦 18/12/20 19:29:28
   首先, linux下的进程地址空间布局是这样子的: 可以看到 整个进程地址空间从上到下地址变化是从高地址到低地址的! 32 位系统有 4G 的地址空间,其中0x08048000-> 0xbfffffff 是用户空间,0xc0000000~0xffffffff 是内核空间,包括内核代码和数据、与进程相关的数据结构(如页表、内核栈)等。其实就是大体上就是下面这样: 另外, %esp 执行栈顶,往低地址方向变化; brk/sbrk 函数控制堆顶往高地址方向变化。也就是说栈是向下生长的.(堆向上生长,这样可以充分利用空间) 知道了这些,我们就可以开心的来看代码了^-^ 保存现场: 协程在从 RUNNING 到 SUSPEND 状态时需要保存运行栈,即调用 coroutine_yield 之后挂起协程,让出CPU的过程。 原理:就是将该协程运行时候的所有数据转而存储到每个协程所对应的结构中,为了在下次回到这个协程时能回到之前的执行点继续执行,那么你会想问,那这个协程运行的时候的栈在哪?我们来看代码 继续阅读 >>


刘生玺 18/12/20 15:33:26
文章目录一、MyBatis的执行流程二、自动映射和驼峰映射三、#{...}和${...}的区别四、获取自增主键值和非自增主键值五、传递多个参数的4种方式1. 顺序传参法2. 使用Map传参3. 使用注解@Param传参4. 通过JavaBean传参六、使用resultMap进行关联查询resultType和resultMap实现一对一查询小结七、动态sql1. if元素2. foreach元素八、模糊查询使用CONCAT()函数进行拼接: 一、MyBatis的执行流程 首先要有MyBatis配置文件,包括MyBatis全局配置文件和MyBatis映射文件。 MyBatis通过读取配置文件信息,构造出SqlSessionFactory,即会话工厂。 通过SqlSessionFactory会话工厂创建SqlSession会话,SqlSession的作用是操作数据库。 SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器来操作数据库的。 Executor执行器要处理的SQL信息是 继续阅读 >>


贺含悦 18/12/20 13:55:53
文章目录Connector classConnector.hConnector.ccTcpClientTcpClient.hTcpClient.cc判断连接建立成功 Connector class Connector class负责主动发起连接, 他不单独使用, 而是包含在TcpClient class内, Connector不负责创建 socket, 只负责连接的建立, 包括这其中的错误处理和重连 需要考虑的难点: socket 是一次性的, 当 connect 出错, 我们必须关闭该 socket, 重新创建一个 socket, 但是Connector是可以反复使用的, 错误码和Acceptor不同, EAGAIN 是真的出错了, 表明本机临时端口暂时用完了( ephemeral port ), 需要延期重试, “正在连接” 的的返回码是 EINPROGRESS, 重试的间隔应该逐渐延长, 需要处理自连接 Connector.h #ifndef MUDUO_NET_CONNECTOR_H # 继续阅读 >>


吕子健 18/12/19 16:14:02
文章目录功能描述TcpConnection.hTcpConnection.cc 功能描述 TcpConnection class用来表示一个 TCP 连接, 不可再生, 如果这个连接断开, 那么该TcpConnection就失去了意义 TcpConnection中包含有封装好的读写 buffer, 用来收发数据 TcpConnection的生命周期由智能指针shared_ptr来管理, 具体在下面的注释中有 TcpConnection对象有四个状态, 表示连接的正在建立, 建立完成, 处于断开 (TcpConnection不主动关闭一个连接, 都是等客户端主动关闭), 已经断开 TcpConnection.h #ifndef MUDUO_NET_TCPCONNECTION_H #define MUDUO_NET_TCPCONNECTION_H #include <muduo/base/noncopyable.h> #include <muduo/base/StringPiece.h 继续阅读 >>


吕子健 18/12/18 21:40:11
统一事件源的实现 我们在编写高性能服务器的代码时,通常会需要处理很多的信号,如下所示 时间事件 信号 数据读 数据写 网络异常 为了程序的性能,鲁棒以及代码的优化,通常会将所有的这些需要处理的任务包装成事件添加至多路复用函数的事件集中处理。 一般信号处理时会将一些信号屏蔽,为了不屏蔽这些信号太久,同时也不至于主逻辑被冲散,一种解决方案是:信号处理函数只是简单的通知主循环(用于处理I/O事件)并告诉信号值,真正的信号处理逻辑被主循环调用,根据信号值做出相应的处理。信号处理函数和主循环之间通常用管道做通信。信号处理函数从管道的写端写入信号值,主循环从管道的读端读取信号值。因为主循环本身就要利用I/O复用函数监听链接进来的socket,所以将这个管道一并注册进I/O复用函数就能在主循环中及时得到信号到来的通知。 总结起来就是 频繁地直接处理信号不利于程序的性能和可靠性,我们把信号也包装成一个事件,添加进多路复用函数的事件集里进行统一处理 很多优秀的I/O框架库和后台服务程序都统一处理事件和I/O事件,比 继续阅读 >>


刘嘉辉 18/12/18 21:16:11
文章目录AcceptorAcceptor.hAcceptor.ccTCPServerTCPServer.hTCPServer.cc Acceptor Acceptor class用来接收一个新的 TCP 连接 Acceptor.h #ifndef MUDUO_NET_ACCEPTOR_H #define MUDUO_NET_ACCEPTOR_H #include <functional> #include <muduo/net/Channel.h> #include <muduo/net/Socket.h> namespace muduo { namespace net { class EventLoop; class InetAddress; /// /// Acceptor of incoming TCP connections. /// class Acceptor : noncopyable { public: typedef std:: 继续阅读 >>


吕子健 18/12/17 20:42:15