上一次我学习了进程与线程,大略地知道了它们联系与区别,这次我学习了进一步学习了进程的相关知识:应用进程跨越网络的通信。
1、什么是系统调用?
在学习应用进程之间的网络通信之前,我们应该首先了解什么是系统调用。现在大多数的操作系统采用系统调用的机制在应用程序和操作系统之间转化控制权。例如应用程序要对一个文件进行操作,它不能直接去找那个文件然后操作。应用程序的进程首先要调用一个请求函数(系统调用)请求对这个文件的操作,操作系统进程得到此请求后会创建一个文件描述符(后面将详述)给应用程序进程,应用程序进程再根据系统提供的文件描述符去操作文件。
系统调用和函数调用实际上是非常类似的。如果应用进程要从操作系统或得某项服务,应用进程就必须启动系统调用(类似调用函数),对系统的的控制权(本质可能是进程下的线程对CPU的占用)就从应用进程传递给了系统调用接口(函数接口),此接口再把控制权转交给操作系统,操作系统把这个调用转交给其内部的某个过程,过程执行完毕(类似函数执行完毕)就把控制权转交给应用进程。
2、应用编程接口
由于现在 TCP/IP 协议大多被嵌入到了操作系统中,因此上图调用 TCP 协议是由操作系统控制的。
3、客户进程、服务器进程的通信
客户进程与服务器进程的通信可以简单地描述如下图:
以上是针对TCP连接的,由于UDP是不是面向连接的,所以不会有listen 和 accept。服务器进程虽然创建了套接字,但是其中的端口号和IP地址时空的,调用bind可以获取端口号和IP地址。客户端进程没有调用套接字,端口号随机分配。这其中最重要的就是accept的调用,当服务器主进程调用accept后,将会发生以下步骤:
- 主进程为每一个新的连接请求新建一个套接字(连接套接字),以及创建一个从属进程;
- 从属进程用新建的连接套接字与客户进程建立连接,然后在这个连接上传送和接受数据;
- 主进程利用原来的套接字重新调用accept,继续接受下一个连接请求。
(过程也可以从上图看出),这样服务器就能同时处理多个连接,并发工作。
4、套接字的创建和套接字描述符
Linux中套接字类型有:
- SOCK_STREAM:流式套接字,提供面向连接、可靠的数据传输服务,数据按字节流、按顺序收发,保证在传输过程中无丢失、无冗余。TCP协议支持该套接字。
- SOCK_DGRAM:数据报套接字,提供面向无连接的服务,数据收发无序,不能保证数据的准确到达。UDP协议支持该套接字。
- SOCK_RAW:原始套接字。允许对低于传输层的协议或物理网络直接访问,例如可以接收和发送ICMP报文。常用于检测新的协议。
当应用进程要进行网络通信时,它需要请求套接字soket系统调用,这样操作系统会为它创建一个套接字,并为这个应用进程分配一定的资源。那么如何来标识这些资源呢?操作系统用到了套接字描述符来标识这些资源,并把这个参数传递给应用进程。下面就解释一下套接字描述符到底十个什么东西。
套接字描述符在linux中成为套接字描述符,在Windows中通常被成为句柄,是一个较小的整数。每一个整数唯一对应一个套接字描述符表,这些表存储在固定的内存中,以方便应用进程通过参数(套接字描述符—较小的整数)找到对应的套接字描述符表项,再通过表项中的指针访问套接字的内容,因为此指针指向存放套接字内容的地址。这样套接字的创建就完成了。那么创建的套接字里面有什么内容呢?
套接字的数据内容如下图(以服务器端为例):