熟知套接字和应用层
必须有一种方法让你对指定的计算机打开连接,登录上去,告诉它你需要什么文件,并且控制文件的传输。(如果你想到不同的应用,例如计算机邮件,某种类似的协议也是需要的。)这个是由“应用层协议”完成的。应用层协议位于 TCP/IP协议的顶部。也就是说,当他们需要发送一个消息,他们会把那个消息交给TCP层。TCP层确保它输送到另一端。因为TCP层和IP层处理了所有的网络方面的细节,应用层协议可以认为一个网络连接是一个简单的字节流,就像一个终端或一条电话线。
在探究关于应用程序的更多细节之前,我们必须描述一下怎么找到一个应用。 假设你想传送一个文件到一台Internet地址为128.6.4.7电脑上。要开始这个过程 ,你需要的不仅仅是Internet地址。你必须连接到另一端的FTP服务器。一般而言 ,网络程序专门用来完成一些特定的任务。大多数系统用不同的程序去处理文件传输,远程终端登录,邮件等等。当你连接到128.6.4.7时,你必须指定你要和 FTP服务器对话。这是通过每个服务器持有的熟知套接字来实现的。前面已经说过 TCP层用端口号来区别不同的会话。用户程序通常使用或多或少的随机产生的端口号。然而特定的端口号被指派给等待请求的程序。例如,如果你要传送一个文件 ,你要启动一个称为“ftp”的程序。它将使用某个随机数(假定为1234)来打开一个连接,这个随机数就是它这端的端口号。然而它将指定21作为另一端的端口号。这是FTP服务器的正式端口号。注意,有两个不同的程序与此有关。你运行 ftp在你这边。这个程序被设计成用来接受从你的终端发出的命令并把他们传递到另一端。在另一台机器上与你会话的程序是FTP服务器。与其说它被设计为一台交互式的终端,还不如说它是被设计用来接受来自网络连接的命令的程序。没有必 要让你的程序使用一个熟知套接字号,因为没有人会去查找它。但是服务器必须 有熟知端口号,这样子才能让人们对它们打开连接并且开始向它们传送命令。每个程序的正式端口号都取之于“已分配号码”。
注意,一个连接实际上由一组4个数来描述:各端的Internet地址和各端的TCP层 端口号。每个数据报都包含所有这4个数在里边。(Internet地址在IP头里,TCP 层端口号在TCP头里。)为了互相区别,任意两个连接都不能拥有相同的一组数字 。但是只要其中的任何一个数字不同就足够啦。例如,很有可能同一台机器的两 个用户要传送文件到相同的另一台机器,这就可能形成具有以下参数的连接:
Internet地址 TCP 端口
连接 1 128.6.4.194, 128.6.4.7 1234(源), 21(目)
连接 2 128.6.4.194, 128.6.4.7 1235(源), 21(目)
既然有关相同的机器,Internet地址就是一样的。因为它们都进行文件传输,所以连接的一端涉及FTP的熟知端口号。唯一不同的东西是用户运行的程序的端口号 。这已经足以形成区别了。一般来说,至少连接的一端要求网络软件给它分配确保是唯一的端口号。通常这个由用户端做,因为服务器必须使用熟知端口号码。
TCP为实现多路复用使用了端口号。因为端口号是在各个TCP实体上独立使用的,因此从网络整体看来,端口号并非具有唯一性的标识符。构造套接号后,网络上具有唯一性的IP地址和端口号结合在一起,才构成唯一能识别的标识符。
套接字基本概念
套接字是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。可以将套接字看作不同主机间的进程进行双向通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中,通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。套接字通常和同一个域中的套接字交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序)。各种进程使用这个相同的域互相之间用Internet协议簇来进行通信。
套接字可以根据通信性质分类,这种性质对于用户是可见的。应用程序一般仅在同一类的套接字间进行通信。不过只要底层的通信协议允许,不同类型的套接字间也照样可以通信。套接字有两种不同的类型:流套接字和数据报套接字。
套接字工作原理
要通过互联网进行通信,你至少需要一对套接字,其中一个运行于客户机端,我们称之为ClientSocket,另一个运行于服务器端,我们称之为ServerSocket。
根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
所谓服务器监听,是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
所谓客户端请求,是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
所谓连接确认,是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
套接字工作过程:
1. 创建套接字并绑定
调用socket函数创建一个待使用的套接字。通过这个函数的参数定义了套接字的类型、网络地址类型和使用的协议,具体参数的定义请参考例程和Microsoft MSDN,在这里我们就不具体论述了。
使用bind函数绑定套接字,通过它将创建好的套接字与本地地址和本地端口联系起来。
一个完整的网络通讯必须具备协议、本地地址、本地端口、远地地址和远地端口5个基本要素,在创建套接字时确定了协议类型,而在绑定套接字时确定本地地址和本地端口,远地地址和远地端口的确认需要通过调用下面讨论的连接和通讯类函数实现。
2. 建立socket连接
在客户端使用connect函数和服务器建立连接。
而在服务器端则使用listen监听来自客户的连接请求并通过调用accept函数接受客户的连接请求。
3. 通过套接字进行网络通讯
发送数据使用write、writev、send、 sendto 和sendmsg函数,其中前三个用于面向连接的数据发送,另外两个用于无连接的数据发送。
接收数据使用read、 readv、 recv、 recvfrom和recvmsg,他们和上面的发送函数是一一对应的。
4. 关闭套接字,释放Winsock资源
在通讯结束后,使用closesocket关闭不再使用的套接字并调用WSACleanup释放底层的资源。