Reactor
Folders and files
Name | Name | Last commit date | ||
---|---|---|---|---|
parent directory.. | ||||
当前文件夹下的所有程序都是本人创建的。用于实现C++服务器程序。 目前支持的功能如下: 1.支持对文档搜索与推荐 2.动态加载配置文件,通过信号函数来通知程序去动态加载配置文件 3.支持http,xml,rtps,rtp解析 4.支持定时器 5.支持线程池加Reactor模式的高并发 6.支持分布式rpc。 7.支持多种数据库 --------------2024.8.11------------------ TODO: 1.开发部署脚本 2.web管理 Tcp 网络编程的本质就是三个半事件 1.连接的建立,包括服务端接受新连接和客户端成发起连接。Tcp连接一旦建立,客户端和服务端就是平等的,可以各自收发数据 2.连接的关闭,包括主动断开(close, shutdown)和被动断开(read(2)返回0); 3.消息的发送,文件描述符可读。这是最为重要的一个事件,对它的处理方式决定了网络编程的风格(是阻塞还是非阻塞,如何处理分包, 应用层的缓冲如何设计,等等)。 3.5 消息发送完毕。对于低流量的服务,可以不必关心这个事件;另外,这里的"发送完毕"是指数据写入操作系统的缓冲区,将由TCP协议栈 负责数据的发送与重传,不代表对方已经收到了数据。 这其中有很多难点,也有很多细节需要注意,比方说: 如果要主动关闭连接,如何保证对方已经收到全部数据? 如果应用层有缓冲(这在非阻塞网络编程中是必需的,见下文),那么如何保证 先发送完缓冲区中的数据,然后再断开连接?直接调用close(2)恐怕是 不行的。 如果主动发起连接,但是对方主动拒绝,如何定期(带back-off 地)重试? 非阻塞网络编程该用边沿触发(edge trigger)还是电平触发(level trigger)? 如果是电平触发,那么什么时候关注EPOLLOUT事件?会 不会造成busy-loop?如果是边沿触发,如何防止漏读造成的饥饿? epoll(4)一定比poll(2)快吗? 在非阻塞网络编程中,为什么要使用应用层发送缓冲区? 假设应用 程序需要发送40kB数据,但是操作系统的TCP发送缓冲区只有25kB剩余 空间,那么剩下的15kB数据怎么办? 如果等待OS缓冲区可用,会阻塞当前线程,因为不知道对方什么时候收到并读取数据。因此网络库应该 把这15kB数据缓存起来,放到这个TCP链接的应用层发送缓冲区中,等socket变得可写的时候立刻发送数据,这样“发送”操作不会阻塞。 如果应用程序随后又要发送50kB数据,而此时发送缓冲区中尚有未发送的数据(若干kB),那么网络库应该将这50kB数据追加到发送缓冲区 的末尾,而不能立刻尝试write(),因为这样有可能打乱数据的顺序。 在非阻塞网络编程中,为什么要使用应用层接收缓冲区? 假如一次读到的数据不够一个完整的数据包,那么这些已经读到的数据是不是应该先暂存在某个地方,等剩余的数据收到之后再一并处理? 见lighttpd关于\r\n\r\n分包的bug。 假如数据是一个字节一个字节地到达,间隔10ms,每个字节触发一次文件描述符可读(readable)事件,程序是否还能正常工作? lighttpd在这个问题上出过安全漏洞14。 在非阻塞网络编程中,如何设计并使用缓冲区? 一方面我们希望减少系统调用,一次读的数据越多越划算,那么似乎应该准备一个大的缓 冲区。 另一方面,我们希望减少内存占用。如果有10000个并发连接,每个连接一建立就分配各50kB的读写缓冲区(s)的话,将占用1GB内存, 而大多数时候这些缓冲区的使用率很低。muduo用readv(2)结合栈上空间 巧妙地解决了这个问题。 如果使用发送缓冲区,万一接收方处理缓慢,数据会不会一直堆积在发送方,造成内存暴涨? 如何做应用层的流量控制? 如何设计并实现定时器?并使之与网络IO共用一个线程,以避免锁。 这些问题在muduo的代码中可以找到答案。 判断发送方主动关闭的方法是使用recv函数。并且把第四个参数设置为MSG_PEEK。再用recv从要判断的连接的文件描述符对应的内核文件 的输入缓冲区中拷贝而非读取数据。如果返回值为0,则对等方已经关闭。 但这种方法只能判断对等方主动关闭的情况,而对于网络异常等问题无法检测。这些问题一般使用心跳协议。也可以在socket中 设置keepalive