socket通常也称作“套接字”,应用程序通常通过“套接字”向网络发出请求或者响应网络请求。socket位于传输层之上,应用层之下。socket函数基本为系统调用,它是操作系统向网络通信应用程序提供的函数接口。
Linux套接字编程完全兼容Unix套接字编程,两个平台编程方法是一致的。读者可以重点掌握TCP套接字编程和UDP服务器编程。
1.1.1 套接字说明
Linux&Unix的I/O内涵是系统中一切都是文件。当程序在执行任何形式I/O的时候,程序是在读或者写一个文件描述符从而实现操作文件。但是,这个文件可能是一个socket网络连接、目录、FIFO、管道、终端、外设、磁盘上的文件。socket是使用标准Linux文件描述符和其他进程进行通信的。
利用socket编程, 会涉及流(stream)、连接(connection)、阻塞(block)、非阻塞(non-block)、同步(synchronous)、异步(asynchronous)、长连接、短连接、IP地址、端口、字节顺序等概念,这些概念将在后文加以介绍。
(1)套接字网络层次说明
图18-1画出了套接字位于网络中的层次,它位于传输层之上,应用层之下。socket编程是通过一系列系统调用完成应用层协议。如ftp、telnet、http等应用层协议都是通过socket编程来实现。
图18-1 套接字层次图
套接字是对网络中应用进程之间进行双向通信的抽象,提供了应用层进程利用网络协议栈交换数据的机制。
从套接字所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议栈进行通信的接口,是应用程序与网络协议栈进行交互的接口。
从实现的角度来讲,套接字系统函数是一个复杂的软件模块,包含了一定的数据结构和许多选项,由操作系统内核管理。
从使用的角度来讲,利用套接字函数编程非常简单。
总之,套接字是网络通信的基石。套接字函数是一种网络通信API,程序员可以用之开发网络程序。
(2)IP地址与端口
端口是指网络中面向连接服务和无连接服务的通信协议端口,它是一种抽象的软件结构,包括一些数据结构和I/O(基本输入输出)缓冲区。
IP地址用来标识网络中不同主机的地址,而端口号就是标识同一台主机上不同网络通信进程的地址,IP地址和端口号合起来标识网络中唯一的进程。
如果把IP地址比作一间房子 ,端口就是出入这间房子的门。真正的房子只有几个门,但是一个IP地址的端口可以有65536(即2^16)个之多。端口是通过端口号来标记的,端口号只能是整数,范围是从0 到65535(2^16-1)。其中端口1~1024是系统保留端口。
其中一次socket通信连接,会涉及源IP地址、源端口、目的IP地址、目的端口四个要素。源IP地址、源端口标识客户端进程,其中源端口为操作系统随机分配的;目的IP地址、目的端口标识服务端进程,其中目的端口是由应用程序指定的。
(3)socket编程说明
Linux系统是通过提供套接字(socket)函数来进行网络编程的。socket技术提供了在TCP/IP模型各个层上的编程支持,该技术是在内核处理收到的各层协议数据,然后应用程序以文件操作方式接收内核传来的数据。应用程序对文件处理是通过一个文件描述符来进行的,socket文件描述符可以看成普通的文件描述符来进行操作,这就是Linux设备无关性的好处,可以通过对文件描述符读写操作来实现网络间数据流的传输。
(1)TCP建立连接
TCP连接时,服务器和客户端需要通过三路握手才正式建立连接。下图18-2画出了客户端与服务端三路握手的实现。
图18-2 TCP三路握手图
TCP连接的过程说明如下:
① 服务器绑定端口进行通信侦听,通过调用socket、bind、listen函数完成。
② 客户端通过调用connect进行发起对服务端的连接,客户端发送一个SYN分节x告诉服务器客户端使用的端口以及TCP连接的初始序号。
③ 服务器在收到客户端的SYN报文后,将返回一个SYN+ACK的报文,ACK分节x+1(请求序号加1)表示客户端的请求被接受,SYN分节y为服务器请求客户端进行确认。
④ 客户端发送ACK分节y+1对服务端SYN分节y进行确认,此时三路握手完成。
(2)TCP连接关闭
TCP连接关闭时双方需要通过四次会话,其流程如下图18-3所示。
图18-3 TCP连接关闭图
TCP一般需要用四个分节终止一个连接,终止具体流程描述如下:
① TCP客户端发送一个FIN分节M,用来关闭客户到服务器的数据传送。
② 服务器收到这个FIN,它发回一个ACK,确认序号为收到的M序号加1。
③ 服务器开始关闭客户端的连接,发送一个FIN分节N给客户端。
④ 客户段发回ACK报文确认,并将确认序号设置为收到序号N加1。
(3)TCP连接中的分组交换
图18-4是TCP连接中的分组交换图,它画出了客户端和服务器连接的全过程,并标明通信过程中的连接状态。其中TIME_WAIT状态是执行主动关闭的那一端(本图的客户端)进入这种状态,在该状态的持续时间是2MSL(最长分节生命周期),这个状态的存在是为了保证ACK分节发送的成功。
图18-4 TCP连接中的分组交换
摘录自《深入浅出Linux工具与编程》