初识端口
什么是端口?
我们知道,网络层提供主机到主机的通信,而传输层提供进程到进程的通信 。在网络层中,IP 地址是识别主机的标识符,网络包通过 IP 地址来寻找主机;相对地,在传输层中,端口是主机上进程的标识符,网络包通过 IP 地址到达主机后,又通过端口号来寻找对应进程。即,端口号用来唯一标识主机进程 。
一个 IP 地址和一个端口号组成了 套接字地址 ,套接字地址唯一标识了网络中的进程。而客户端和服务器端的 IP 地址与端口,以及传输层协议,共同组成了 五元组 ,用来标识唯一通信。
客户端程序使用 临时端口号 定义自己,之所以叫“临时端口号”,是因为其生命周期较短,本次使用完该端口,下一次就不一定再使用。临时端口号通常选择 49152 ~ 65535之间的数。
服务器端也需要使用端口号定义自身,但此端口号不能随机选择,否则客户端访问服务器端时,将不知道其端口号。所以服务器必须使用 公用端口号(well-know port)
ICANN范围
公用端口: 0 ~ 1023
注册端口: 1024 ~ 49151
动态端口: 49152 ~ 65535
端口号在计算机中占 16 位 bit ...
详解ARQ协议
自动重传请求(Automatic Repeat-reQuest,ARQ)是 OSI 模型中 数据链路层 和 传输层 的错误纠正协议之一。它通过使用 确认 , 超时 ,校验和 这三个机制,在不可靠服务的基础上实现可靠的信息传输,且是一种面向连接的协议。
ARQ 协议到底属于数据链路层的协议还是传输层的协议?
ARQ 是一种可以在不可靠的数据通道上可靠地传输数据的方案,所以其实链路层和传输层都用了 ARQ ,并不专属某一层。例如,数据包到达数据链路层的网卡和交换机后会进行 FCS 校验,如果错误则直接丢弃;又如在 TCP(传输层)中,数据包的 TCP 报头有 seq 序列号,用于检测失序和丢失。
ARQ 包含三个协议:停止 - 等待协议(SW),回退N帧协议(GBN),选择重传协议(SR) 。下面对各个协议进行详细分析。
停止 - 等待协议(SW)
发送方和接收方都只有大小为 1 的滑动窗口 。每当发送方发送一个分组时,就会开启一个计时器,一旦超时,就重发分组,这意味着,当收到接收方发来的 ACK 前,发送方都必须将已发送的分组留在窗口中而不可删除。
ARQ 协议通过 序号(s ...
CSAPP
计算机系统漫游
生成可执行文件的过程
graph LR
hello.c--> B{预处理器}-->hello.i-->L{编译器}-->hello.s-->G{汇编器}-->K("hello.o")-->A{链接器}-->可执行目标文件
Z("printf.o")-->A
hello.i 文件是在 hello.c 的基础上进行了宏替换,头文件展开等操作。
编译器将C代码转变为汇编语言程序,而汇编器将汇编语言程序转变为机器语言,而不是汇编器将C代码转变为汇编语言。
汇编语言为不同的高级语言提供了相同的输出语言。任何高级语言都需要先转为汇编语言,因为汇编语言才是和机器语言一一对应的。 汇编语言的种类取决于电脑使用的 CPU 指令架构。所以机器代码和汇编代码的移植性比高级语言差许多。
printf 函数在单独预编译好的 printf.o 的文件中,这个文件需要以某种方式合并到 hello.c 文件中,链接器就负责此过程。
系统的硬件组成
总线
总线在各个部件中传输信息字节。 ...
转专业失败总结
失败不是结果,它发生在每一个瞬间。
由于笔试失误,我转计算机专业失败了,一年的期待落空,一年的努力化为泡影。迷茫和矛盾充斥内心,一方面,我难以接受这样的结果,计算机是我的兴趣,其他学科的学习可以说是煎熬,我难以想象未来的学习该怎么继续;另一方面,我接受这次失败,因为它是必然的,过去一年的许多瞬间都加固了它的必然性。痛定思痛,与其虚假的彷徨,不如反思自己的失败。
为什么说失败发生在每一个瞬间?
明知转专业看重绩点,却依然忽视本专业课程的学习,过度看重转专业面试和所谓的计算机“项目”经验,耗费了许多经历在小项目的制作上。
笔试考的是基础的算法题,为什么依然“失误”——无他,手不熟尔。编程学而不精,没有注重编程基础能力,总是以自己的“项目”为傲,不愿走出舒适区。
浪费了大量时间和精力在无关的事情上。我总是以自己不打游戏为傲,以为自己因此赢得了不少宝贵的时间。去他妈的,都是自我安慰。。。即使没打游戏,我还是浪费了一大把时间,关键是我还说不出来这些时间浪费在哪了。
不专注,没有沉下心来做事。总认为本土木专业的课程耗费我的“宝贵时间”,但却没见自己把这些“宝贵时间”用在计算机上, ...
shared_ptr与虚析构
123456789101112131415class A {public: A(); ~A();private: Data* data;};class AX : public A {public: AX(); ~AX();private: AXData* ax_data;};
以下不会存在内存泄漏的写法是?
A. AX* p = new AX(); delete p;
B. A* p = new AX(); delete p;
C. shared_ptr<A> p = shared_ptr<A>(make_shared<AX>()); delete p;
D. shared_ptr<A> p = shared_ptr<A>(make_shared<A>()); delete p;
正确答案: A,C,D
解析:
B:基类析构函数没有声明为 virtual ,所以 p 所指的对象析构时,不会调用基类的析构函数。
D:正常情况,显然不会内存泄漏。
C:sha ...
重载,覆盖与隐藏
此三者的区别是针对继承关系下的成员函数而言。
详解assert与if
一. assert的作用
和 if 的作用基本无异,都用来检测一些边界条件和进行安全性检查,如:
指针是否为空?
被除数是否为 0?
函数调用的返回结果是否有效?
打开一个文件是否成功?
使用格式:assert(exp);
assert 会计算表达式 expression ,如果其值为假(即为0),那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行 。
从功能上而言,下面的两种写法等效:
1234567assert(0 != b);//上下两者在功能上等价if (0 == b){ fprintf(stderr, "b is zero..."); abort();}
同时需要注意,assert 是宏,而非函数:
12345#ifdef NDEBUG #define assert(condition) ((void)0)#else #define assert(condition) /*implementation defined*/#endif
从上面assert的宏可看出:
如 ...
高质量编写strcpy()
《高质量C++编程指南》的作者林锐博士,曾去微软中国研究院面试,而面试官让他写一个简单的strcpy()函数。林博士很惊讶,心想这有什么难的。而半小时后,林博士大汗淋漓地走出了”考场“。
这样一个小不点函数,面试官从三个方面考察:
代码风格
出错处理
算法复杂度分析
由此可见,编写出合格的strcpy()是不容易的,它尤其考验程序员的基本功和思维的严密性。
下面直接给出最终代码,再逐步剖析:
12345678910char* strcpy(char* des, const char* src){ if(des == src) return src; assert(des != NULL); assert(src != NULL); char* temp = des; while((*des++ = *src++) != '\0'); return temp;}
参数类型: 将src的内容拷贝到des中,并不会修改src。所以为了防止误操作改变src ,需要声明为const char*。 ...
高质量C++编程指南
图片不是很清楚,附上导图pdf和本书pdf:高质量C++编程pdf,提取码:gzwb
本书由林锐博士撰写,他的个人经历便可以映射出本书的价值:
我从读大学到博士毕业十年来一直勤奋好学,累计编写了数十万行 C++/C 代码。有 这样的苦劳和疲劳,我应该称得上是编程老手了吧?
我开发的软件都与科研相关(集成电路 CAD 和 3D 图形学领域),动辄数万行程序, 技术复杂,难度颇高。这些软件频频获奖,有一个软件获得首届中国大学生电脑大赛软件展示一等奖。在 1995 年开发的一套图形软件库到 2000 年还有人买。罗列出这些“业绩”,可以说明我算得上是编程高手了吧?
可惜这种个人感觉不等于事实。
读博期间我曾用一年时间开发了一个近 10 万行 C++代码的 3D 图形软件产品,我内心得意表面谦虚地向一位真正的软件高手请教。他虽然从未涉足过 3D 图形领域,却在 几十分钟内指出该软件多处重大设计错误。让人感觉那套软件是用纸糊的华丽衣服,扯 一下掉一块,戳一下破个洞。我目瞪口呆地意识到这套软件毫无实用价值,一年的心血白化了,并且害死了自己的软件公司。
人的顿悟通常发生在最心痛的时刻,在沮丧 ...
explicit关键字
explicit关键字
C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数只能显式调用, 而不能充当转换构造函数(当构造函数只有一个参数或其他参数都有缺省值时)。 跟它相对应的另一个关键字是implicit,。类构造函数默认情况下即声明为implicit。
为何尽量对单参数构造函数使用explicit?
12345678910111213class A{ public: A(int x){ cout<<"我被用了"<<endl; }};void func(A a){}int main( ){ func(1);// 被隐式转换为func(A(1)) ,本来是1却被自动调用了A(1)这就是拷贝初始化 //输出:"我被调用了" return 0;}
而实际上,func(1)可能只是操作失误。
什么时候下,构造函数可以充当转换构造函数?
当构造函数只有一个参数且没有explict关键 ...