admin管理员组

文章数量:1565370

不是很懂,大概浏览下,理清一些基础概念。

深入理解计算机系统
1.4 命令行解释器(命令/可执行文件)
cpu从程序计数器(PC)指向的内存处,读取指令,解释指令的位,(主存,寄存器,算数/逻辑单元ALU)执行指令的操作(加载,存储,操作,跳转),更新PC,执行下一条指令
shell读入指令字符,到寄存器,再到内存
直接存储器存取DMA,数据从磁盘到内存
高速缓存存储器cache,访问局部区域的数据和代码

1.6 上一层存储器是低一层存储器的高速缓存(L3是主存的,主存是磁盘的)
1.7 操作系统:文件(IO设备的抽象),虚拟内存(主存,磁盘的抽象),进程(cpu,内存,IO的抽象),虚拟机(os+cpu+主存+IO的抽象)
上下文切换:cpu并发执行多个进程
上下文:PC,寄存器文件当前值,主存内容
内核:os代码常驻主存的部分,内核并非进程,而是os管理全部进程所用的代码和数据结构的集合

进程的虚拟地址空间,地址由低到高依次是:
程序代码和数据
堆,进程开始运行时malloc出来的
共享库
栈,函数调用
内核虚拟内存,为内核保留

1.9 并发:一个同时具有多个活动的系统
并行:用并发使一个系统运行的更快
多核cpu,L1 cache存放(指令+数据)
超线程:一个线程等待数据进入cache,此时cpu继续去执行另一个线程

2.1 虚拟地址空间:将DRAM,闪存,磁盘,特殊硬件和操作系统软件结合起来,为程序提高一个看上去统一的字节数组
C语言中一个指针的值,是某个存储块的第一个字节的虚拟地址,C编译器维护着指针的类型信息
每个程序对象可以视为一个字节块,程序本身就是一个字节序列
字长:指明指针数据的标称大小
计算机,32位字长限制虚拟地址空间为4GB,即超过4e9 字节,64位是16EB,1.84e19字节
int为4字节
小端法:机器选择在内存中按照从低到高的有效字节的顺序存储对象,包括:大多数Intel兼容机,Android,iOS
文本数据比二进制数据具有更强的平台独立性:使用ASCII码作为字符码的任何系统上都得到同样的jiegui结果,与字节顺序和字大小规则无关
所有的编译器/机器组合,都对有符号数使用算术右移,无符号数必须逻辑右移
2.2 使用宏保证: 不论代码如何编译,都能生成正确格式的字符串
java中单字节数据是byte,而非char,因此兼容任何机器
有符号数到无符号数的隐式转化,导致漏洞,因此避免使用无符号数

3.2
程序计数器PC,给出将要执行的下一条指令在内存中的地址;
整数寄存器文件,存储地址和整数数据,记录程序状态,过程的参数和局部变量,函数返回值;
条件码寄存器,保存最近执行的算术逻辑指令的状态信息。用来实现控制或数据流中的条件变化;
一组向量寄存器,存放整数,浮点数值。

程序内存:程序的可执行机器码,OS需要的一些信息,管理过程调用和返回的运行栈,用户分配的内存块。
程序内存用虚拟地址来寻址,OS管理虚拟地址空间,将其翻译成实际内存中的物理地址。

3.4 操作数指示符: 操作数用来指示出一个操作要用的源数据,放置结果的目的位置。
操作数三种类型:立即数(常数值),寄存器(某个寄存器的内容),内存引用(根据有效地址访问内存位置)

数据传送指令:源操作数,指定一个立即数,存储在寄存器或内存中,目的操作数指定一个位置,是一个寄存器或者一个内存地址。
X86-64加了一条限制,传送指令的两个操作数不能都指向内存地址。于是,将一个值从内存位置复制到另一个内存位置,就需要两条指令:将源值加载到寄存器中,将寄存器值写入目的位置。
间接引用指针(即用*p读/写值),就是将该指针放在一个寄存器中,然后在内存引用中使用这个寄存器。
像局部变量通常保存在寄存器中,而非内存中,因此要更快。
X86-64中,程序栈存放在内存中某个区域,栈向下增长。

3.6 实现条件操作的传统方法是通过使用控制的条件转移,但十分低效,替代的策略是使用数据的条件转移。
cpu使用流水线作业实现高性能,采用非常精密的分支预测逻辑猜测跳转指令是否会执行。另外,无论测试数据是什么,编译出来使用条件传送的代码所需时间都是大约8个时钟周期,保证cpu更容易保持流水线是满的。

3.7 过程的形式:函数(function),方法(method),子例程(subroutine),处理函数(handler)等。
过程的动作,所包括的机制:传递控制,传递数据,分配/释放内存。
当X86-64过程需要的存储空间超出寄存器能够存放的大小时,就会在栈上分配空间。这个部分称为过程的栈帧。为了提高时间和空间效率,X86-64过程只分配自己所需要的栈帧部分,比如对于许多过程有6个或更少的参数,那么所有的参数都可以通过寄存器传递。如果,所有的局部变量都可以保存在寄存器中,而且该函数不会调用任何其他函数(叶子过程,树结构),就可以这样做。

局部数据放在内存中:
寄存器不足够存放所有本地数据;
取址运算符’&’,要求必须有一个地址;
数组或结构,要求必须通过某种结构访问到。

寄存器组是唯一被所有过程共享的资源。
每个过程调用在栈中都有它自己的私有空间,因此多个未完成调用的局部变量不会相互影响。此外,栈的原则很自然地就提供了适当的策略,当过程(如函数)被调用时分配局部存储(如函数私有的状态信息,甚至局部变量的存储),当返回时释放存储。

3.9 数据对齐:许多计算系统对基本数据类型的合法地址做出了一些限制,要求某种类型对象必须是某个值K(2,4,8)的倍数,简化了形成cpu和内存系统之间接口的硬件设计。intel建议对齐数据提高内存系统的性能。(数据对齐并不是操作系统的内存结构的一部分,而是cpu结构的一部分。)

3.10
int(*f)(int*);f是一个指针,指向以int*为参数并返回int的函数的指针。
int *f(int*);f是一个函数,以int*为参数并返回int*
C语言对数组引用不进行任何边界检查,局部变量和状态信息(如保存的寄存器值集合返回地址)都存放在栈中。
缓存区溢出:让程序指向本来不愿执行的函数,常见的通过计算机网络攻击系统安全。通常给程序一个字符串,字符串包含一些可执行代码的字节编码,称为攻击代码。
一些字节会用一个指向攻击代码的指针覆盖返回地址。
攻击形式:攻击代码使用系统调用启动一个shell程序,给攻击者提高一组os函数。
攻击代码执行一些未授权的任务,修复对栈的破坏,表面上正常返回到调用者。
对抗缓冲区溢出攻击:栈随机化,栈破坏检测,限制可执行代码区域。

4.0 指令集体系结构:一个cpu支持的指令和指令的字节级编码。
4.1 内存从概念上来说就是一个很大的字节数组,保存着程序和数据。
4.2 存储器:为了产生时序电路,也就是有状态并且在这个状态上进行计算的系统,必须引入按位存储信息的设备。存储设备都是由同一个时钟控制,时钟是一个周期性信号,决定什么时候要把新值加载到设备中。

两类存储设备:
时钟寄存器(寄存器)存储单个位或字,时钟信号控制寄存器加载输入值;
随机访问存储器(内存)存储多个字,用地址选择该读写哪个字。比如cpu的虚拟内存系统(硬件和os软件结合起来的一个很大的地址空间)、寄存器文件(寄存器标识符作为地址)
寄存器:
硬件寄存器(硬件中,寄存器直接将它的输入和输出线连接到电路的其他部分)
程序寄存器(机器级编程中,寄存器代表的是cpu中为数不多的可寻址的字,地址是寄存器ID)
4.3 一条计算指令的6个阶段:
取指(fetch)从内存读取指令字节,地址为程序计数器PC的值。从指令中抽取指示符字节的两个四位部分(icode指令代码和ifun指令功能)
译码(decode)从寄存器文件读入最多两个操作数
执行(execute)算术逻辑单元ALU执行指令指明的操作,计算内存引用的有效地址,或增加/减小栈指针。
访存(memory)将数据写入内存,或从内存读出数据。
写回(write back)最多写两个结果到寄存器文件。
更新PC(PC update)将PC设置成下一条指令的地址。
cpu无限循环,执行这些阶段。
原则:从不回读:cpu从来不需要为了完成一条指令的执行而去读由该指令更新了的状态。
4.4 流水线化:提高系统吞吐量,轻微增加延迟。为了提高时钟频率,现代cpu采用很深(15+)流水线。
吞吐量=1条指令/(组合逻辑时间+加载寄存器时间) GPS每秒千兆条指令
延迟=组合逻辑时间+加载寄存器时间 ps皮秒
SEQ+(Sequential+,电路重定时):更新PC阶段在一个时钟周期开始时执行,而非结束时执行。添加流水线寄存器,得到PIPE流水线。

4.5 栈的返回地址预测PC:大多数程序,过程调用和返回是成对出现的。大多数函数调用,会返回到调用后的那条指令。高性能cpu运用了这个属性,在取指单元放入一个硬件栈,保存过程调用指令产生的返回地址。每次执行过程调用指令时,将其返回地址压入栈中,当取出一个返回指令时,就从这个栈中弹出顶部的值,作为预测的返回值。预测错误时提供恢复机制。通常预测很准确,这个硬件栈对程序员不可见。
数据冒险的类型:
程序寄存器(寄存器文件的读写在不同阶段进行),程序计数器(更新和读取程序计数器的冲突),内存(程序自我修改代码),条件码寄存器,状态寄存器(指令流经流水线,影响程序状态)
避免数据冒险:暂停,转发,加载/使用数据冒险,避免控制数据冒险,

5.13 优化程序性能:
高级设计:选择适当的算法和数据结构
基本编码原则:消除连续的函数调用,如果可能,将计算移到循环外,妥协程序的模块性;
消除不必要的内存引用,引入临时变量,最后的值计算出来后,再存放到数组或全局变量中;
低级优化:展开循环,降低开销;使用多个累加变量和重新结合等技术;用功能性的风格重写条件操作;

6.1.1 随机访问存储器
非易失去性存储器: 存储在ROM设备中的程序称为固件, 计算机系统通电后, 会运行固件.

访问主存: Intel系统使用北桥和南桥的芯片组, 分别将cpu连接到内存和IO设备

6.1.2 磁盘存储
磁盘控制器, 维护着逻辑块号和实际物理磁盘扇区之间的映射关系.(逻辑块号===>盘面, 磁道, 扇区)
通用串行总线, USB

P454

unix编程艺术
之前的笔记忘了,就记得一个算法是基于数据结构,而不是平级的;
另外就是不要太重复做前人的工作。

4.1 API:隔离模块,定义整个体系
4.2 紧凑性:C,Python(半紧凑)C++(反紧凑,不指望谁完全理解)
正交性:重构的原则性目标
重复数据:是否可以一个由另一个生成,是否可以是同一来源
缓存滋生bug
4.3 C语言:硬件之上尽可能薄的胶合层,完美即是无可删减
4.4 程序分解成胶合层连接的库集合,特别是共享库(Win上的动态链接库DLL)
4.5 OO语言(面向对象):使陷入过渡分层陷阱的倾向(如果你知道自己在做什么,三层就够了,否则十七层也没用)、丧失优化的机会
4.6 全局变量,模块化的毒药,模块大小,函数大小(缩进层数),内部api的每一单元是否不受其他代码影响,api入口点是否超过7个,模块入口点数量和分布(模块复杂性与接入点数量的平方成正比)

5.0 unix两种设计:设计将应用数据存储在永久存储器中的文件格式,在协作程序中(可能会通过网络)传递数据和命令的应用协议。两者都与内存数据结构的序列化有关。
序列化(保存)操作称为列集marchaling;反向的(载入)操作称为散集。

5.1 运行控制文件(配置文件),通常体积很小,信息流单向,从启动时文件读取流向应用程序的设置。
数据文件,体积多大都有,格式的属性和命名资源联系在一起,可读可写,信息流双向。

PNG格式指定了字节顺序,整数字长,优先顺序,和(但缺少)字段间的填充。
PNG文件由一系列字节块(chunk)构成,每个块都是自描述格式,块类型+块长度开头。

5.3 数据文件元格式:
DSV分隔符分隔值格式:如存储验证用户登录并开始用户会话所需的用户数据的/etc/passwd文件,冒号是默认的分隔符。(当数据为列表,名称为关键字,记录很短时,DSC格式最适用),类似的有CSV的逗号分隔。
RFC 822 格式:互联网电子邮箱信息的文本格式,Usenet使用这种格式,HTTP1.1以及后续版本也使用这种格式。
Cookie-Jar格式
Record-Jar格式:Cookie-Jar和RFC 822 的结合,适合图类似DSC文件,但又有可变字段数目而且可能伴有无结构文本的字段属性关系集合。
XML格式:类似HTML,适合于RCF 822元格式不太好处理,有复杂递归或嵌套数据结构的格式。读取XLM格式的软件系统XML解析器。谨慎选择,牢记KISS原则。
Windows INI格式:适合于数据围绕指定的记录或部分能够自然分成“名称-属性对”两层组织结构。但不适合于递归树形结构(不如XML),对于简单的名称-值关系列表则大材小用(不如DSV)。

Unix文本文件格式的约定:
如果可能,以新行符结束的每一行只存一个记录(让文本格式的解析器不受结束符是LF还是CR-LF影响);
如果可能,每行不超过80个字符(终端视窗浏览);
使用“#”引入注释;
支持反斜杠约定;
在每行一条记录的格式中,使用冒号或任何连续的空白作为字段分隔符。
不要过分区别tab和whitespace;
优先使用16进制而非8进制(16进制更容易与字节,32,64位字对应起来,效率也高一点);
以及其他等待约定。。。。

5.3 CLI服务器模式:服务器进程通常由inetd之类统一控制程序调用,服务器程序从stdin接收命令,将响应发送到stdout。
端对端(end-to-end)设计守则。

SMTP协议是邮件发送者启动事务处理的“推push”协议;而POP3是邮件接受者启动事务处理的“拉pull”协议,将邮件从机器上通过网线接收到自己电脑上。

5.4 HTTP请求采用类似RFC-822/MIME格式的消息:
消息头(识别+认证信息)
第一行是对URI指定的某个资源的方法调用。(方法:GET获取、PUT修改、POST发送给表单或后台进程。)
BEEP块可扩展交换协议。
基于XML文档的三个协议:XML-RPC,SOAP,Jabber。

6.0 美是抵御复杂的终极武器。
优雅是力量与简洁的结合,不是一种奢侈。
数据格式和应用协议进行文本化,带来:透明性和可显性:可显性降低入门门槛,透明性减少代码中的存在成本。
6.1 GCC编译器:预处理器,解析器,代码生成器,汇编器,链接器。
6.3 代码是活代码,睡代码还是死代码(可维护性)。
选择简单的算法:拿不准,穷举。

7.2 进程间通信IPC技法:
把任务转给专门程序:廉价的进程生成,程序调用另一个程序做专门任务。
管道,重定向和过滤器:管道依赖于,每个程序一开始至少有两个IO数据流可用,stdin,stdout,文件描述符0,1,许多程序可作为过滤器,从stdin读,向stdout写。

重定向操作:
命令写入文件ls>foo
文件通过命令输入到stdoutwc<foo
当前目录列表的字符数/字符/行数ls | wc,分页显示ps -aux | more
管道线中的所有阶段的程序是并发运行的。
管道的缺点是单向性
包装器wrapper(安全性包装器,Bernstein链)

从进程:编写主/从进程对时,一个好方法是,让主进程支持命令行开关或环境变量,来允许调用者设置自己的从进程命令。这利于调试,从监视和记录主从进程之间事务处理的辅助程序中调用真正的从进程,会给你带来很多方便。 如果发现主从进程的交互不再微不足道(进程间通信协议无足轻重的,比如进度条显示程序),剩下的,也许是考虑使用套接字或共享内存,走更趋对等结构的路了。

对等进程间通信:临时文件,风险:
如果文件删除前进程中断,则遗留垃圾数据。
程序的多个实例使用一个名字作为临时文件名,产生冲突。(因此shell脚本的惯例是在;临时文件中包含“$$”符号,脚本运行的当前进程ID号,保证文件名的唯一性)
如果知道临时文件写入的位置,则可以覆盖文件来产生攻击。

信号:
SIGTERM终止:清除临时文件,强制把最新更新刷新回数据库
SIGKILL立即杀死:不能被阻塞或另外处理

套接字:
通过socket通信的两个程序通常存在双向字节流,字节流即是按序的,又是可靠的(底层网络的错误检测,重发)。
socket描述符一旦获得,行为基本上和文件描述符一样。
socket比起读写操作,如果接受机器没有ACK确认,发送机器的TCP/IP栈将超时。即使不知道哪些省部级已经被接收到,也仍然必须正确工作。
判断交付:本地IO(是/否),socket IO(是/否/或许)
无论协作进程在何处安置,这些socket通常都是用于双向IPC的正确方法。性能压力促使你使用共享内存,临时文件,但是最好设想代码增加分布式操作。经过socket强化的分离地址空间是一个特性,不是bug。

共享内存:
在现代的Unix中,共享内存发实现通常依靠使用mmap,把文件、映射成可以被多个进程共享的内存。POSIX定义了具有API的shm_open功能,支持把文件作为共享内存使用,提示os,不要把伪文件刷到磁盘上。
对共享内存的访问不能通过类似于读写调用的规范自动序列化,所以处理共享的程序必须自己处理竞争和死锁。典型方法是在共享段适应信号量变量,产生的问题与多线程类似,但容易管理。
使用共享内存和信号量功能:可以避免通过网络栈复制数据的开销。大型商业数据库(Oracle,DB2,Sybase,Infomix)大量使用这种技术。

7.3 streams网络流,RPC远程过程调用。
线程,是那些进程生成昂贵,IPC功能薄弱的os所特有的概念。
线程问题:全局内存,没有自动封装,时序依赖。
尽管线程没有快速转换进程上下文的开销,但锁定共享数据结构以防止相互干涉的开销同样昂贵。
X Server执行速度能达到数百万次/秒,其使用poll/select循环实现,而非线程。对于图形服务器这种对性能敏感的程序来说,上/解锁的成本太高了。
这也是unix内核的对称多处理设计的长期问题,资源锁定变得精细,锁定导致的延迟也迅速增加。
Windows和传统mac OS 自带的线程模型和中段功能,与unix差别非常大,即使很简单的线程程序,移植也需要很大精力。

7.4 在某种程度上,程序在生命期内交换数据,也就是各种方法:临时文件,交互性更强的主从进程关系,socket,RPC,和其他一些双向IPC方法。
方法的差别主要是:程序如何建立通信,何时何地完成信息的列集和散集,可能产生何种缓冲问题,如果确保获取信息的原子性(一边的单个发送行为,在另一边成为单个的接收事件)。
降低复杂度,通常是将程序划分为client和server对

这段话很到位啊 !
线程支持的并非不同程序间通信,而是单个程序的一个实例内的某种分时形式。线程并不是把大程序分解成简单的小程序的方法,实际上是一种性能调整(performance hack)问题。而且线程还有其他问题。
将大程序分解成小程序,使用有限的共享内存和信号量,SIGIO的异步IO,poll/select,而非线程。python(Queue队列、进程、Gevent协程、Select\Poll\Epoll异步IO与事件驱动)
真实世界的编程其实就是管理复杂度的问题。能够管理复杂度的工具都是好工具,但当这些工具的作用不是控制而是增加复杂度的时候,最好扔掉,从零开始。永远不要忘记这一点,它是Unix智慧的重要组成部分。

P190

unix网络编程
1.1 应用层(用户进程),TCP/IP协议(系统内核协议栈)
1.2 socket函数创建tcp套接口,也就是tcp端点tcp endpoint;

socket:套接口
sockfd:套接口描述字(套接字),socket的返回值,socket函数返回值<0,则创建失败
一个套接口,对应多个套接字(可以复制,继承),而一个套接字只对应一个套接口
read返回0(远程端关闭),负(发生错误)
tcp不提供记录结束标记,需如果应用需要,则自己去实现
包裹函数把原函数首字母改成大写:简化代码,保证测试每个函数调用,检查是否报错

协议数据单元PDU:
TCP/IP协议族,应用层实体:数据data(tcp应用进程),或记录record(udp应用进程)
传输层实体:分节segment,数据报datagram
网络层实体:分组(包)package,分成片段fragment
数据链路层实体:帧frame
每一次pdu及用于封装上一层的pdu,也用于本层内部的协议通信


1.7 接口信息,数值地址netstat -ni
路由表,netstat -rn

1.10 posix可移植操作系统接口:
进程原语(fork,exec,信号,定时器)
进程环境(用户ID,进程组)
文件目录(IO函数)
终端IO
系统数据库(保密字文件,用户组文件)

2.3 UDP无连接服务:可以使用一个socket接连给多个服务器发送数据,服务器也是。
2.4 TCP重传4-10分钟,RTT(C/S往返所花时间)算法;
对于两份信息,TCP保证传输顺序,而UDP不能保证;
TCP提供流量控制(动态的通告窗口),UDP不是;
TCP是全双工的,UDP可以是全双工。

图为TCP11种状态

2.5 建立TCP连接:
服务器listen,被动打开;
客户connect,主动打开,发送SYN分节
服务器确认SYN,发送SYN;
客户确认SYN,回复服务器;

连接终止:
(通常是客户主动关闭,HTTP则是服务器主动关闭)
发送端close,主动关闭,发送FIN分节;
接收端接收FIN,被动关闭,接收FIN作为文件结束符给应用进程,停止收数据;
接收端应用进程调用close,关闭套接口,发送FIN;(进程终止时,sockfd关闭,进程收到终止信号而关闭,此时TCP连接上也会发送FIN)
发送端确认接收FIN

如上图,TCP的发送和接收共2个分节,但还需要8个额外的分节开销。UDP则不需要。

2.6 TIME_WAIT状态:
实现终止TCP全双工连接的可靠性:保证最终ACK的发出,保证四次挥手的4个分节的任一分节不丢失。
允许老的重复分节在网络中消逝:如果发生断开,则再次打开,此时要处理旧的连接在网络中正在传输的数据(如路由器断开,数据迷路,数秒/分钟后才找到出路),TIME_WAIT状态维持2MLS的持续时间,保证每一端收到的分组存活MLS秒后被丢弃。

2.7 端口号:
服务器,21个众所周知端口(0-1023),客户,临时端口(动态,私有端口,49152-65535)
保留端口,即众所周知端口(0-1023),只能分配给超级用户的套接口。因此分配这些端口的服务器启动时,必须有超级用户的特权。

套接口对:两端的两对IP/PORT元组,IP/PORT称为一个套接口。
TCP必须查看套接口对的所有四个元素,才能确定由哪个端点接收到达的分节。因为要区分监听套接字(即父进程)和已连接套接字(fork出的子进程)

2.9 最大传输单元MTU,以太网1500字节。
应用进程写数据到套接口的过程:
应用进程调用write,内核从进程的缓冲区拷贝所有数据到套接口的缓冲区。
如果进程缓冲区大于套接口缓冲区,或套接口缓冲区还有其他数据,则进程被挂起(睡眠)
套接口默认是阻塞的,直到所有数据发送完,内核从write系统调用返回成功,此时代表可以重新使用进程缓冲区。并不代表对方TCP/对方应用进程收到数据。
对方TCP确认收到数据,发送ACK,本方才删除套接口缓冲区中已确认的数据,TCP为此保留数据拷贝。

TCP以MSS大小的块发送数据给IP,IP加上IP头构成数据报,查找路由表项,确定外接出口,把数据报传输给链路,IP可能分片再传给链路。
链路有输出队列,如果队列满,则丢弃分组,沿协议栈向上(链路到IP,IP到TCP)返回错误。TCP收到错误,以后重传,而进程对此并不清楚。

3.2 大多数套接口函数,都需要一个指向套接口地址结构的指针作为参数。每个协议族都定义它自己的套接口地址结构。ANSI C通过将套接口地址结构的指针声明为void *类型,可以实现套接口函数能够处理来自所支持的任何协议族的套接口地址结构。
IPv4地址和ICP或UDP端口号在套接口地址机构中总是以网络字节序来存储。
3.3 除了指针,套接口地址结构的长度也作为参数来传递,其传递的方式取决于结构的传递方向:从进程到内核,还是反回来。

从进程到内核(结构的整数大小)bind,connect,sendto:将函数大小告诉内核,内核在写这个结构的时候不会越界。
从内核到进程(指向表示结构大小的整数的指针)accept,recvfrom,getsockname,getpeername,函数返回时,结构大小是一个结果(值-结果参数),告诉进程,内核在此结构中确切存储了多少信息。
3.4 由于网络协议必须指定一个网络字节序,网际协议在处理多字节整数时,使用大端字节序。

4.2 socket函数
函数socket指定了协议族和套接口类型,得到小的非负返回值,即套接口描述字socket descriptor,简称套接字sockfd。protocol参数设置为0,除非用在原始套接口上。
AF_前缀代表地址族,PF_前缀代表协议族。现存大多代码中,头文件<sys/socket.h>中为一给定协议定义的PF_值总是与此协议的AF_值相等。

4.3 客户connect之前不是非要bind:
进程可以把一个特定的IP地址捆绑到它的套接字上,不过这个IP地址必须属于其所在的网络接口之一。对于TCP客户,这就为在该套接字上发送的IP数据报指定了源IP地址;对于服务器,则限定了该套接字只能接收那些目的地为这个IP地址的客户连接。
TCP客户端通常不把IP地址捆绑到它的套接字上。当连接套接字时,内核将根据所用的外出网络接口来选择源IP地址,而所用外出接口则取决于到达服务器所需的路径。
如果TCP服务器没有吧IP地址绑定到它的套接字上,内核就把客户发送的SYN的目的IP地址作为服务器的源IP地址。

客户端connect函数,激发TCP的三次握手过程,且仅在连接建立成功或出错时返回。socket函数创建套接口,然后就处于CLOSED状态,connect导致从CLOSED状态进入SYN_SENT状态,如果握手成功,转到ESTABLISHED状态。如果connect失败,则socketfd不再可用,必须关闭socketfd再重新调用socket,不能再对此套接口再调用connect。

P92

鸟哥的Linux私房菜基础学习篇第四版v2.0
0.4.2 操作系统
核心的系统调用接口会主动的将 C 程序语言的相关语法转成核心可以了解的任务函数, 那核心自然就能够顺利运行该程序了!
应用程序有时会需要一些危险的、权限很高的指令,如果把这些权限放心地交给用户程序是很危险的(比如一个进程可能修改另一个进程的内存区,导致其不能运行),但是又不能完全不给这些权限。于是有了系统调用,危险的指令被包装成系统调用,用户程序只能调用而无权自己运行那些危险的指令。另外,计算机硬件的资源是有限的,为了更好的管理这些资源,所有的资源都由操作系统控制,进程只能向操作系统请求这些资源。操作系统是这些资源的唯一入口,这个入口就是系统调用。

操作系统 核心功能:
系统调用接口, 程序管理, 内存管理, 文件系统管理, 设备的驱动

2.1
各个元件或设备在 Linux 下面都是 “ 一个文件! ”

2.2.2
分区:数据的安全性,系统的性能考虑

4.2.2 常用命令
bc 计算器
exit = ctrl + d
shitf + pageUp 翻页
who 谁在线上
netstat -a 网络
ps -aux 后台程序
sync 数据写盘
whatis 命令功能

p218

本文标签: 本书笔记网络Unix