<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[一位菜鸡的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/Rengachan</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; Rengachan]]></copyright><item><title><![CDATA[TCP详解 （四）流量控制和拥塞控制]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/113099723</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/113099723</guid><author>Rengachan</author><pubDate>Mon, 25 Jan 2021 00:22:42 +0800</pubDate><description><![CDATA[文章目录什么是流量控制滑动窗口什么是拥塞慢启动、拥塞避免快重传、快恢复
什么是流量控制
流量控制实际上是一种快等慢的策略，也就是说，如果发送者发送数据过快，接收者来不及接收，就会导致接收者的缓存溢出，使得分组丢失。为了避免分组丢失，就需要对发送者的发送速度进行控制，这就是流量控制。流量控制根本目的是防止分组丢失，它是构成TCP可靠性的一方面。
我们在平时喝水的时候都会注意一口水喝多少，以免喝太多反而吐出来，这大概也是流量控制。
滑动窗口
TCP所使用的是被称为滑动窗口协议的流量控制方法。该协议允许发送方在停]]></description><category></category></item><item><title><![CDATA[TCP详解 （三）Nagle算法和延迟确认]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/113098431</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/113098431</guid><author>Rengachan</author><pubDate>Sun, 24 Jan 2021 22:55:55 +0800</pubDate><description><![CDATA[文章目录延迟确认Nagle算法Nagle算法遇上延迟确认关闭Nagle算法

一些有关TCP通信量的研究如[Caceresetal.1991]发现，如果按照分组数量计算，约有一半的TCP报文段包含成块数据（如 FTP、电子邮件和 Usenet新闻），另一半则包含交互数据（如Telnet和Rlogin）。如果按字节计算，则成块数据与交互数据的比例约为 90 %和10 %。这是因为成块数据的报文段基本上都是满长度的，而交互数据则小得多。

为了同时处理上述两类数据，
延迟确认
对于键入一个交互命令时所产生的数据]]></description><category></category></item><item><title><![CDATA[TCP详解（二）三次握手与四次挥手]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/112791136</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/112791136</guid><author>Rengachan</author><pubDate>Sun, 24 Jan 2021 21:56:12 +0800</pubDate><description><![CDATA[文章目录连接的建立和终止三次握手为什么不是两次？为什么不是四次？四次挥手等待2MSLTCP的状态变迁图
上一篇文章说了TCP是一个面向连接的协议，双方之间必须先建立一条连接才能够进行数据的通信。本文就来讨论一下，一个TCP连接是如何被建立以及终止的。
连接的建立和终止
要了解在连接建立和终止的过程中发生了什么，最好的方法就是抓包观察。以下两图是访问某个网页过程中TCP连接建立和断开时的数据包。这就是大名鼎鼎的TCP三次握手和四次挥手，我们会对其逐行进行分析。
最前面的TCP表明该连接使用TCP协议，后面就不]]></description><category></category></item><item><title><![CDATA[TCP详解（一）服务和首部介绍]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/112782175</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/112782175</guid><author>Rengachan</author><pubDate>Sun, 24 Jan 2021 21:56:04 +0800</pubDate><description><![CDATA[文章目录引言TCP的服务TCP首部
引言
TCP全称传输控制协议（Transmission Control Protocol），它是一种传输层通信协议，提供了面向连接的、可靠的字节流服务。本文将会简要介绍TCP为应用层提供的服务以及TCP首部中的各个字段，并在后续的文章中详细介绍。
TCP的服务
TCP提供一种面向连接的、可靠的字节流服务。
什么是面向连接：一种网络协议,依赖发送方和接收器之间的显示通信和阻塞以管理双方的数据传输。网络系统需要在两台计算机之间发送数据之前先建立连接的一种特性。
举个例子，AB]]></description><category></category></item><item><title><![CDATA[GDB调试程序常用方法及命令整理]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/111238952</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/111238952</guid><author>Rengachan</author><pubDate>Tue, 15 Dec 2020 22:27:04 +0800</pubDate><description><![CDATA[文章目录GDB常用命令表GDB使用一.启动GDB二.运行程序三.设置和显示参数四.查看源代码五.查看变量及变量类型查看变量查看变量类型六.断点1.设置断点2.查看断点3.删除断点4.禁止/允许断点5.清除断点六.单步调试七.设置监测点八.调用路径九.退出GDB
GDB常用命令表




GDB命令
格式
含义
简写




list
list line1,line2
列出文件的代码
l


print
print p
打印变量内容
p


break
break [行号或函数名称]
设置断点
b


con]]></description><category></category></item><item><title><![CDATA[vim常用操作整理]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/111054809</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/111054809</guid><author>Rengachan</author><pubDate>Fri, 11 Dec 2020 23:24:13 +0800</pubDate><description><![CDATA[文章目录普通模式到编辑模式普通模式到指令行模式光标移动复制粘贴与删除搜索替换
本文只包含一些最基本最常用的操作
普通模式到编辑模式




按键
操作




i, I
进入输入模式(Insert mode)：i 为『从目前光标所在处输入』； I 为『在目前所在行的第一个非空格符处开始输入』


a,A
进入输入模式(Insert mode)：a 为『从目前光标所在的下一个字符处开始输入』 ；A 为『从光标所在行的最后一个字符处开始输入』


o,O
进入输入模式(Insert mode)：o 为『在目前光]]></description><category></category></item><item><title><![CDATA[C++ 模板特例化]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/110692316</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/110692316</guid><author>Rengachan</author><pubDate>Sat, 05 Dec 2020 17:08:25 +0800</pubDate><description><![CDATA[文章目录介绍函数模板特例化类模板特例化
介绍
模板作为C++泛型编程的基础十分重要，其使得一份代码能用于处理多种数据类型。而有些时候，我们会希望对一些特定的数据类型执行不同的代码，这时就需要使用模板特例化(template specialization)。
函数模板特例化
首先说一个重要的，函数模板的特例化并不是函数重载，每一个特例化实际上是提供了另一个模板定义式，因此特例化不影响函数匹配。
特例化一个函数模板时，必须为模板中的每个参数都给出实参，关键字template后跟一个&lt;&gt;
templa]]></description><category></category></item><item><title><![CDATA[C++11 可变参数模板]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/110099378</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/110099378</guid><author>Rengachan</author><pubDate>Tue, 24 Nov 2020 23:49:59 +0800</pubDate><description><![CDATA[介绍
一个可变参数模板是一个接受可变数目参数的模板函数或模板类。可变数目的参数成为参数包。存在两种参数包：模板参数包 ，表示零个或多个模板参数；函数参数包，表示零个或多个函数参数。
用一个省略号来指出一个模板参数或函数参数表示一个包。在模板参数列表中，class…或typename…指出接下来的参数表示零个或多个类型的列表；一个类型名后面跟着的省略号表示零个或多个该给定类型的非类型参数的列表。在函数参数列表中，如果一个参数的类型是一个模板参数包，则此参数也是一个函数参数包。例如：
//Args是一个模板参数]]></description><category></category></item><item><title><![CDATA[C++11 std::move]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/110007047</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/110007047</guid><author>Rengachan</author><pubDate>Mon, 23 Nov 2020 21:18:41 +0800</pubDate><description><![CDATA[文章目录定义std::move如何工作
标准库move函数时使用右值引用的模板的一个很好的例子。研究move是如何工作的可以帮助巩固对模板的理解和使用。
move函数只有唯一一个功能：获得一个绑定到左值上的右值引用，以通过右值引用的方式使用该左值。move可以接受任何类型的实参，因此它必然是一个函数模板。它的实现基于C++ 引用折叠和右值引用参数中的两个规则。
定义
标准库这样定义move:
template&lt;typename T&gt;
typename remove_reference&lt;T&]]></description><category></category></item><item><title><![CDATA[C++ 引用折叠和右值引用参数]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109997911</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109997911</guid><author>Rengachan</author><pubDate>Mon, 23 Nov 2020 19:35:32 +0800</pubDate><description><![CDATA[假定有一个模板如下
tempalte&lt;typename T&gt; void f(T&amp;&amp;);

如果有一个i为一个int对象，那么我们可能认为类似f(i)这样的调用是不合法的，因为通常不能将右值引用绑定到一个左值上：
int i = 0;
f(i);//向一个右值引用形参传入一个左值实参，是否正确？

事实上，C++在正常绑定规则外定义了两个例外规则允许这种绑定。这两个例外规则是move标准库设施正确工作的基础。


第一个例外规则影响右值引用参数的推断如何进行：当将一个左值传递给函数]]></description><category></category></item><item><title><![CDATA[C++ final和override关键字]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109879931</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109879931</guid><author>Rengachan</author><pubDate>Sat, 21 Nov 2020 15:42:29 +0800</pubDate><description><![CDATA[防止继承
C++11提供了一种防止继承发生的方法：在类名后面跟一个关键字final。
class NoDerived final {
	/* */
};
//编译错误：无法将final类类型作为基类
class Derived :public NoDerived{
	/* */
};


]]></description><category></category></item><item><title><![CDATA[C++ 动态绑定]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109862957</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109862957</guid><author>Rengachan</author><pubDate>Fri, 20 Nov 2020 20:15:42 +0800</pubDate><description><![CDATA[定义
动态绑定是在运行期间发生的绑定，发生动态绑定的函数的运行版本由传入的实际参数类型决定，在运行时觉得函数的版本，所以动态绑定又称运行时绑定，动态绑定是C++的多态实现的一种形式。
在C++中，当使用基类的引用或指针调用一个虚函数时将发生动态绑定。
实现原理
C++中的动态绑定通过虚函数实现。而虚函数是通过一张虚函数表（virtualtable）实现的，拥有虚函数的类在实例化时会创建一张虚函数表。这个表中记录了虚函数的入口地址，当派生类对虚函数进行重写时，虚函数表中相关虚函数的地址就会被替换，以保证动态绑]]></description><category></category></item><item><title><![CDATA[C++11 智能指针(三) unique_ptr]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109716661</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109716661</guid><author>Rengachan</author><pubDate>Mon, 16 Nov 2020 14:23:21 +0800</pubDate><description><![CDATA[目录介绍创建一个unique_ptr转移所有权特殊情况
介绍
一个unique_ptr独占它所指向的对象。某个时刻只能有一个unique_ptr指向一个给定对象。unique_ptr被销毁时，它指向的对象也会被销毁。一个unique_ptr不支持普通的拷贝或赋值:
unique_ptr&lt;string&gt; p1(new string{"abc"});
unique_ptr&lt;string&gt; p2(p1);//错误：不支持拷贝
unique_ptr&lt;string&gt; p3;//错误]]></description><category></category></item><item><title><![CDATA[C++11 智能指针(二) weak_ptr]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109680537</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109680537</guid><author>Rengachan</author><pubDate>Sat, 14 Nov 2020 19:02:47 +0800</pubDate><description><![CDATA[目录介绍创建一个weak_ptr
介绍
weak_ptr是一种不控制所指向对象生存期的智能指针，它指向一个由shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变它的引用计数。一旦最后一个指向某个对象的shared_ptr被销毁，对象就会被释放，即使weak_ptr指向该对象，该对象也会被释放。
weak_ptr的操作




操作
说明




weak_ptr&lt;T&gt; w
空weak_ptr可以指向类型为T的对象


weak_ptr&lt;T&gt; w]]></description><category></category></item><item><title><![CDATA[C++11 智能指针(一) shared_ptr]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109648034</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109648034</guid><author>Rengachan</author><pubDate>Fri, 13 Nov 2020 15:43:46 +0800</pubDate><description><![CDATA[目录前言shared_ptr介绍创建一个shared_ptrmake_shared函数shared_ptr的内存泄漏一个简单的shared_ptr实现
前言
C++中使用一对运算符new和delete来管理动态内存：new在动态内存中为对象分配空间并返回一个指向该对象的指针，delete接受一个动态对象的指针，销毁该对象并释放与之关联的内存。
确保在正确的时间释放内存极其困难。有时我们会忘记释放已分配的内存，这种情况下就会产生内存泄漏；有时在尚有指针引用内存的情况下我们就释放了它，这种情况下就产生了一个引用]]></description><category></category></item><item><title><![CDATA[C++11 bind函数]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109628643</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109628643</guid><author>Rengachan</author><pubDate>Wed, 11 Nov 2020 19:44:02 +0800</pubDate><description><![CDATA[文章目录介绍使用bind绑定参数bind的参数顺序绑定引用参数
介绍
标准库bind函数定义在头文件functional中，可以将bind函数看成一个通用的函数适配器，它接受一个可调用对象，并生成一个新的可调用对象来“适配”原对象的参数列表。调用bind的一般形式为：

auto newCallable = bind(callable, arg_list);

其中，newCallable 是一个可调用参数，arg_list 是一个逗号分隔的参数列表，对应于给定的 callable 参数。也就是说，当调用 ]]></description><category></category></item><item><title><![CDATA[C++11 lambda表达式]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109624251</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109624251</guid><author>Rengachan</author><pubDate>Wed, 11 Nov 2020 18:07:07 +0800</pubDate><description><![CDATA[目录介绍lambda优点lambda捕获值捕获引用捕获隐式捕获可变lambda
介绍lambda
一个lambda表达式表示一个可调用的代码单元。可以将其理解为一个未命名的内联函数。与任何函数类似，一个lambda具有一个返回类型、一个参数列表和一个函数体。但与普通函数不同，lambda可能定义在函数内部。一个lambda表达式具有如下形式:
[capture list] (parameter list) -&gt; return type { function body }

capture list(捕]]></description><category></category></item><item><title><![CDATA[vector扩容]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109604104</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109604104</guid><author>Rengachan</author><pubDate>Tue, 10 Nov 2020 18:48:14 +0800</pubDate><description><![CDATA[扩容原理

vector以连续的数组存放数据，当vector空间已满时会申请新的空间并将原容器中的内容拷贝到新空间中，并销毁原容器
存储空间的重新分配会导致迭代器失效
因为分配空间后需要进行拷贝，编译器会预分配更多空间以减少发生拷贝影响程序效率
扩容的大小叫做扩容因子，扩容因子由编译器决定，VS的扩容因子为1.5，G++中，扩容因子为2

	vector&lt;int&gt; v = { 1,2,3,4,5,6 };
	cout &lt;&lt; v.capacity()&lt;&lt;' ';
	v.pu]]></description><category></category></item><item><title><![CDATA[处理顺序容器迭代器失效问题]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109603227</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109603227</guid><author>Rengachan</author><pubDate>Tue, 10 Nov 2020 17:48:39 +0800</pubDate><description><![CDATA[编写改变容器的循环程序
添加/删除vector、string或deque元素的循环程序必须考虑迭代器、引用和指针可能失效的问题。程序必须保证每个循环步中都更新迭代器、引用或指针。如果循环中调用的是insert或erase，那么更新迭代器很容易。这些函数都会返回一个有效的迭代器，使用其可以对迭代器进行更新。
//删除偶数元素，复制奇数元素
	vector&lt;int&gt; v = { 0,1,2,3,4,5,6,7,8,9 };
	auto it = v.begin();
	while (it != v.]]></description><category></category></item><item><title><![CDATA[顺序容器中的迭代器失效]]></title><link>https://blog.youkuaiyun.com/Rengachan/article/details/109599785</link><guid>https://blog.youkuaiyun.com/Rengachan/article/details/109599785</guid><author>Rengachan</author><pubDate>Tue, 10 Nov 2020 17:00:43 +0800</pubDate><description><![CDATA[容器操作可能使迭代器失效
向容器中添加元素和从容器中删除元素的操作可能会使指向容器元素的指针、引用或迭代器失效。一个失效的指针、引用或迭代器不再表示任何元素。使用失效的指针、引用或迭代器是一种严重的程序设计错误，很可能引起与使用未初始化指针一样的问题。
向容器添加元素后：

如果容器是vector或string，且存储空间重新分配，则指向容器的迭代器、指针和引用都会失效。如果存储空间未重新分配，指向插入位置之前的元素的迭代器、指针和引用仍有效，但指向插入位置之后的元素的迭代器、指针和引用将会失效。

	//]]></description><category></category></item></channel></rss>