说到数据的发送,也就是数据从主机进入线路的这段旅程,一般需要经过以下几个环节:
应用程序首先得将要发送的数据写入该进程的内存地址空间中,熟悉网络编程的开发者对这个环节一定非常熟悉,通常在程序开发中这只需要一般的运行时变量赋值即可。
应用程序通过系统函数库接口(比如send函数)向内核发出系统调用,由系统内核来进行随后的操作,它将这些数据从用户态内存区复制到由内核维护的一段称为内核缓冲区的内存地址空间。这块地址空间的大小通常是有限的,所有要发送的数据将以队列的形式进入这里,这些数据可能来自于多个进程,每块数据都有一定的额外记号来标记它们的去向。如果要发送的数据比较多,那么该系统调用需要多次进行,每次复制一定的数据大小,这个大小取决于网络数据包的大小以及内核缓冲区的承载能力。重复的系统调用体现在应用编程层面重复调用send函数。
当数据写入内核缓冲区后,内核会通知网卡控制器前来取数据,同时CPU转而处理其他进程。网卡控制器接到通知后,便根据网卡驱动信息得知对应内核缓冲区的地址,将要发送的数据复制到网卡的缓冲区中。注意在以上一系列的数据复制中,数据始终按照连接两端设备的内部总线宽度来复制,也就是字节的整数倍,比如在32位总线的主机系统中,采用PCI-X总线接口的网卡一般使用32位总线宽度,那么从内核缓冲区到网卡缓冲区的数据复制过程中,任何时刻只能复制32位的比特信息。
网卡缓冲区中的数据需要发送到线路中,同时释放缓冲区来获取更多要发送的数据。但是我们知道,只有二进制的数字信号才可以在线路中传输,所以这时候需要对数据进行字节到位的转换,这种转换不难想象,就是将数据的每个位按照顺序依次发出。
发送时,网卡会使用内部特定的物理装置来生成可以传播的各种信号,比如在使用铜线线路时,网卡会根据“0”和“1”的变化产生不同的电信号;而使用光纤线路时,网卡会产生不同的光信号。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。