新建一个专门用于 EventLoop 的线程 实现:启动一个线程,在其中运行 EventLoop::loop() 功能:运行Evenloop 知识点 条件变量使用:当多个线程对同一个变量进行操作时使用条件变量对其进行保护,条件变量同互斥锁一同起作用。 代码及分析: EventLoopThread.h // Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) #include <muduo/net/EventLoop 继续阅读 >>


楚东方 18/03/11 21:35:14
缓冲区(非阻塞 IO 必备) 实现:实现Buffer类 功能:缓冲区,为非阻塞IO暂时存储数据,实现高效IO 知识点: string的函数实现 resize() Resizes the string content to n characters. If n is smaller than the current length of the string, the content is reduced to its first n characters, the rest being dropped. If n is greater than the current length of the string, the content is expanded by appending as many instances of the c character as needed to reach a size of n characters. The second 继续阅读 >>


楚东方 18/03/11 19:22:10
注:本篇博客大部分内容截选自阮一峰老师的DNS 原理入门一文。其中少部分内容是博主自己的理解。 什么是DNS 我们知道,网络本身只能理解数字形式的地址,也就是IP地址。但是直观的IP地址毫无规律,很难让人记住,并且如果使用IP地址浏览一个公司的主页,意味着这家公司一旦将主页移动到了另一台机器上,且该机器具有不同的IP地址,那么必须将该机器的IP地址通知给每一个人。因此人们引入了类似于www.baidu.com这样的域名。而要将域名转换为对应的IP地址,就需要DNS服务器(Domain Name System)。 在早期的ARPANET时代,只有一个简单的hosts.txt文件,它列出了所有的计算机名字和其对应的IP地址。每天晚上,所有的主机都从一个维护此文件的站点将该文件取回,然后在本地进行更新。对于一个拥有几百台大型分时机器的网络而言,这种方法工作的相当好。 然而当几百万台PC连接到互联网以后,问题就出现了。首先这个文件会变的非常大,并且主机名冲突的现象将会频繁发生。为了解决这些问题,DNS服 继续阅读 >>


董恒毅 18/03/05 18:01:22
源码地址:多线程爬虫–抓取淘宝商品详情页URL 项目地址中包含了一份README,因此对于项目的介绍省去部分内容。这篇博客,主要讲述项目的构建思路以及实现细节。 项目概述及成果 首先将本项目使用到技术罗列出来: MySQL数据库进行数据持久化及对宕机情况的发生做简单的处理 Redis数据库做IP代理池及部分已抓取任务的缓存 自制IP代理池 使用多线程执行任务(同步块,读写锁,等待与通知机制,线程优先级) HttpClient与Jsoup的使用 序列化与反序列化 布隆过滤器 之后会对其中使用到的技术进行详细的解释。 本项目如README中所述,还有许多不完善的地方,但IP代理池与任务抓取线程之间的调度与协作基本已无问题。也就是说,在此项目的框架上,如果你想修改其中代码用作其他抓取任务,也是完全可以的。我抓取到的数据所保存的源文件也放在GitHub的README上供大家免费浏览与下载(近90000的商品ID)。 整体思路 首 继续阅读 >>


董恒毅 18/03/02 22:35:30
本文主要是从我写Java网络编程时使用BufferedInputStream和BufferedOutputStream的时候遇到的bug, 来分析BufferedInputStream和BufferedOutputStream的工作机制和简单的源码分析. 1. bug描述 最近在写一个Java网络编程的程序, 其中涉及文件的传输问题, 选择使用BufferedInputStream和BufferedOutputStream来作为网络通信读取数据的方式. 在进行测试的时候, 大文件(几百兆甚至上G)是没有问题的, 但是偶然间测试小文件(十几B)总是失败. 大文件传输成功, 小文件传输不成功, 这说明并不是代码逻辑上的问题, 而应该是某个细节的问题. 经过一番仔细考虑, 去看了看BufferedOutputStream和BufferedInputStream的源码, 终于发现是缓冲区的问题. 小伙伴在看了这博客之后说, 只描述bug对一个陌生人来说不具有太大的参考意义. 所以在这里 继续阅读 >>


祝一迪 18/02/01 12:30:34
今天大概总结一下编写服务端程序常用的编程模型。参考UNP第三版第三十章和陈硕的muduo那本书,强烈建议仔细阅读。注意以下代码只是为了显式框架或者说编程模型,不是完整的程序,深夜写的比较任性,不要见怪。 accept + read/write 这个不是并发服务器,而是迭代服务器(iterative server)。 它一次服务一个客户。不适合长连接,适合 daytime 这种 write-only 短连接服务。 void handle(client_socket, client_address) { while(true) { data = client_socket.recv(4096); if(data) client_socket.send(data); else do_error(); } } while(true){ connfd = server_socket.accept(); handle(client_socket, client_address); } accept 继续阅读 >>


杜肖孟 18/01/25 02:32:20
用于管理一个具体的 TCP 连接,比如消息的接收与发送,完成用户指定的连接回调 connectionCallback。 TcpConnection 构造时接收参数有 TCP 连接的 sockfd,服务端地址 localAddr,客户端地址 peerAddr,并通过 Socket 封装 sockfd。并用 Channel 管理该 sockfd,向 Channel 注册可读、可写、关闭、出错回调函数,用于 Poller 返回就绪事件后 Channel::handleEvent() 执行相应事件的回调。 TcpConnection 有四个状态,简单的状态图: TcpConnection 有一系列用户指定的事件回调函数,比如 TcpConnection::connectionCallback、messageCallback、writeCompleteCallback,这些是用户通过 TcpServer 传给 TcpConnection。当 Poller 返回 TcpConnection 对应的 Soc 继续阅读 >>


杜肖孟 18/01/17 15:04:45
Acceptor 用于 accept 一个 TCP 连接,accept 接受成功后通知 TCP 连接的使用者。Acceptor 主要是供 TcpServer 使用的,其生命期由后者控制。一个 Acceptor 相当于持有服务端的一个 socket 描述符,该 socket 可以 accept 多个 TCP 客户连接,这个 accept 操作就是 Acceptor 实现的。 这里用到了一些封装好的 socket 和地址结构,如 class InetAddress 表示 sockaddr_in 的封装,如可以通过ip地址和port端口生成一个sockaddr_in; class Socket封装了部分关于socket套接字的操作,如Socket::bindAddress(InetAddress&) 将socket和一个sockaddr_in地址绑定,Socket::accept(InetAddress& peerAddr)将一个socket允许连接一个客户端地址peerAddr,Sock 继续阅读 >>


杜肖孟 18/01/12 22:43:03
主要涉及到的类和实现文件有: Endian.h 提供了字节序转换的函数。 Socket.h/Socket.cc socketfd 的封装,提供了绑定地址、开始listen、接受连接等操作,并可设置套接字选项。 InetAddress.h/InetAddress.cc 套接字地址的封装,提供了多种方式初始化一个地址,还提供方法从地址中拿到 ip 和 port。 SocketsOps.h/SocketsOps.cc 封装了 socket 相关的一些操作,提供给 Socket 和 InetAddress 用。 这部分就是基本的 TCP 套接字编程和套接字选项的知识,代码逻辑也很简单,推荐看下 UNP卷一 的相关章节。 下面逐一看下这几个相关的文件。 字节序转换部分(Endian.h) #ifndef MUDUO_NET_ENDIAN_H #define MUDUO_NET_ENDIAN_H #include <stdint.h> #include <endian.h 继续阅读 >>


杜肖孟 18/01/09 15:14:11
muduo 的定时器功能由三个 class 实现,TimerId、Timer 和 TimerQueue。 TimerId 类 它唯一标识一个 Timer 定时器。TimerId Class 同时保存Timer* 和 sequence_,这个 sequence_ 是每个 Timer 对象有一个全局递增的序列号 int64_t sequence_,用原子计数器(AtomicInt64)生成。 它主要用于注销定时器,这样就可以区分地址相同的先后两个 Timer 对象。 namespace muduo { namespace net { class Timer; /// /// An opaque identifier, for canceling Timer. /// /* 带有唯一标识的Timer,主要用于取消Timer */ class TimerId : public muduo::copyable { public: TimerId() : timer_(NULL), 继续阅读 >>


杜肖孟 18/01/07 15:41:05