简介
CPU指令分为普通指令和特权指令,特权指令只有内核能执行,例如对设备的I/O操作就属于特权指令;用户空间只能运行普通指令,如果想要进行I/O操作,如网络通信,操作磁盘文件,就需要系统调用来完成。
当一个进程或程序需要某些数据时,它只能访问或修改属于自己内存空间中的数据,例如进程所需要的数据在磁盘上,它会发起系统调用,通知内核去加载磁盘上的文件,正常情况下,数据首先会加载到内核的内存中,然后在内核的内存空间中把数据拷贝到用户程序的内存缓冲区中,这样,进程就能对数据进行访问或修改。
对于网络I/O,内核中的TCP/IP协议栈有两个缓冲区(send buffer和recv buffer)当网卡收到数据后,网卡通过DMA方式把数据拷贝到recv buffer缓冲区中,随后CPU把数据拷贝到进程的缓冲区中,同理,进程要发送数据,需要发数据发送到send buffer中,通过DMA的方式把数据拷贝到网卡中,网卡通过网络传输到对端。
套接字基础知识
套接字有五部分组成,分别是:
protocol + src_addr + src_port + des_addr + des_port
被称为套接字5元组。套接字通信,其实就是在组建这个5元组。
同步,异步,阻塞,非阻塞
在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式。
同步:当进程发起一个调用时,在没有得到结果时,函数就不会返回。当函数有结果之后,才会返回。
异步:当进程发起一个调用后,这个调用先返回,调用者不会马上得到结果,当这个调用有结果后,通过状态、通知来通知调用者,或通过回调函数处理这个调用。
阻塞和非阻塞指的是,在等待调用结果的时候,它处于一个什么状态。
阻塞:指在调用结果返回前,当前进程处于挂起状态(Cpu不会给线程分配时间片),只有在得到结果之后才会解除挂起状态。
非阻塞:在调用发出后,进程并不会阻塞在该调用上。
阻塞型I/O
假设进程需要进行磁盘I/O操作,它发起了一个系统调用,例如read(),内核首先去加载该文件到内核的内存缓冲区中,然后再拷贝到进程的缓冲区,在这2个过程中,进程都是处于阻塞状态。
非阻塞型I/O
假设进程需要进行磁盘I/O操作,它发起了一个系统调用,例如read(),内核首先去加载该文件到内核的内存缓冲区中,然后再拷贝到进程的缓冲区,在这2个过程中,过程1是非阻塞的,但是过程2是阻塞的
IO复用型I/O
其实是指使用函数来监控是否就绪,常见的有3个复用函数:select()、poll()、epoll(),例如使用了select(),进程发起了一个select()调用,此时,进程会堵塞在该函数上,这样的好处在于,可以同时监测多路I/O,当数据准备好后,select()将会唤醒该进程,然后然进程可以通过发起系统调用来