文档库 最新最全的文档下载
当前位置:文档库 › 基于TCP-IP编程

基于TCP-IP编程

基于TCP-IP编程
基于TCP-IP编程

An Introduction to TCP-IP Programming翻译

1引言

认识到TCP/IP作为一个标准的平台和独立的网络协议和因特网引起的爆炸性的财富,windows套接字API(应用编程接口)开始浮现出来并且成为了windows环境下网络编程的标准。这个文档用以介绍windows套接字编程的基本概念和让你开始创建第一个使用SocketWrench的程序。

SocketWrench是包开发的一部分,Catalyst套接字工具visual版。为了增加理解,并且基本是真实的,使用套件字,提供的套接字工具包含了组建和大多数流行的因特网应用程序协议的组建和元件库,这些协议有FTP,POP3,SMTP和HTTP。更多的有关完成套接字工具包可以参看Catalyst的文章(https://www.wendangku.net/doc/ae8031830.html,)它假设了读者都会是用visual Basic 并且按照了SocketWrench控件。如果你已经对套接字编程很熟悉,你可以轻松跳过本章节。

Windows套接字说明书被包含微软在内的许多公司组成的集团组成,他们共同努力标准化Windows下TCP/IP协议的套件。Windows套接字中最重要的,每个开发者都可以设计自己私有的元件库,即使这些元件库中的元件功能看似是一样的。但是它们的不同点十分重要,因为正是不同的引起了开发人员的选择。最大的限制是,一旦选择了使用私有的元件库开发者将被锁在一个特地的实现中。一个使用私有元件库开发的程序将不能如作者的工作共同工作。Windows套接字可以作为一个解决方案,让开发者和他们的用户资源的选择实现并且保证这些产品会持续的工作。

1.1传输控制协议

当两台计算机希望通过网络交换数据时,有许多的组件需要被实现安排在适当的位置上。当然,物理上的硬件必须存在,典型的是一张网卡和一个用于拨号连接的串行端口。除了这些物理连接,还需要使用协议,在协议中定义了它们之间通信的参数。简单的说,协议是每台计算机必须遵守的“交通规则”,这样网络中的计算机才能交换数据。现在应用的最流行的协议是TCP/IP,他是传输空盒子协议/因特网协议的缩写。

按约定TCP/IP设计到一系列的协议,它们都是基于IP的,并非是一个逻辑的网络把所有的系统直接互联在一起的,一个互联网是许多网络的集合,这些网络组合在一起工程一个单一的虚拟的网络,IP提供了基于任何网络的任何系统可以和另一个不同的系统通信,就好像它们在同一个物理网络上一样。给一个系统,通

常被称作主机,被分配了一个32位的唯一的号码用以在网络上对其识别。通常这个地址被分为四个8位二进制数。这个称为点分十进制,看上去是这样的“192.43.19.64”。地址的一些部分用于标识系统所连接的网络,剩下的用来标识系统本身。无需了解复杂的互联网地址体系的细节,仅仅知道三种典型的地址,它们是“A”“B”和“C”。规则的第一条是“A”类地址给设计成最大的网络,“B”类地址被设计为中等大小的网络,“C”类地址被设计为较小的网络(这个网络中只能大约容下250台主机)。

当一个系统将要使用IP协议在网络上发送数据时,它发送的是离散的单元,这些单元被称作数据报,通常也被称为包。一个数据报有头部和其后根据应有不同而定义的数据。头部包含用于将数据报发送到他的目的地的地址信息。这就像去邮局发送邮件一样。并且和发送邮件一样,不能保证邮件一定到达了它的目的地,事实上,在发送的过程中邮件可能会丢失,被复制或者顺序混乱。无需多说,这些不可靠的成分给软件开发人员带来了很多麻烦。所以真的需要一个可靠地,直达的方法交换数据,她必须是不会对视分组并且不会有乱序。

为了满足这个需要,TCP协议被制定了出来。在IP之上,TCP提供了可靠的双向的诗句流,在这个数据流上读写就好像对一个文件进行读写一样。这样的优势是明显的,应用程序开发人员不需要为处理丢失的分组或者乱序的分组而编写代码,因此可以将注意力集中在应用程序上,而且,因为因为数据时以比特流的方式传输的,已存在的代码可以轻松的就受和改进使用TCP的使用。

TCP是面向连接的协议,换句话说,在两个程序交换数据之前他们必须相互建立一个“连接”,三次握手完成双方将会交换包并且建立初始的序列号(序列号比字面看上去重要,数据报可能乱序的到底,而序列号的作用就是确定每个数据报到底是在什么位置上)。当一个连接成功的建立,一个程序扮演客户机的角色,而另一个扮演服务器。客户机的职责是发起连接,服务器的职责是等待,监听并且回复收到的连接。一点一个连接被建立,在连接关闭之前,双方都可以收发数据。

1.2用户数据报协议

与TCP不同,用户数据报协议(TCP)并不以比特流的形式呈现数据,也不需要你为了与另一个程序交换信息建立连接,数据以离散的被称为数据报的形式发送。这看上去就和原始的IP数据报一样,但是事实上,UDP唯一的特性是提供一个原始的IP数据报纸上的端口号和一个可选的检验和。

UDP有时被认为是不可靠的协议,因为当一个程序发送UDP数据报时,没有办法知道它是否到达了目的地,这就意味着发送方和接收方必须在UDP之上有特色的实现自己的应用协议。许多TCP做的工作现在显然都要由应用程序自己来完成,比如生成校验和,确认收到的包,重传丢失的包等等。

UDP有这么多的现在,你会认为为什么它依然被使用,UDP有TCP不能比拟的优势,速度和包占用的资源。因为TCP是可靠的协议,它使用非常长的帧长来确认数据完整的到达了目的地,所以在网络当中TCP的包非常的多。UDP没有这么大的网络开销,并且被认为比TCP更快。因此在一些对速度要求苛刻的环境下,甚至大多数的包要求在一分钟内达到,UDP就是解决的办法。

1.3主机名

为了一个程序可以与远程的进程可以收发数据,它必须具备非常多的信息,首先是系统的IP地址还有远程程序正在执行。即使这个地址在内部被标上为一个32为数,但是更多的时候被表示为点分十进制或者一个被称为主机名的逻辑名称正如点分十进制中的一个地址,主机名也被重复的分为许多称为域的部分,域是分层的,最高一级的域被定义为网络属于的组织类型,子域进一步的标识特殊的网络。

在这个图中,最高级的域是“gov”(政府代理),“com”(企业组织),“edu”(教育机构),“net”(因特网服务提供者)。完整的域名都是被指定主机名的,并且有一个父子域名,这样就将他们分割开了。举个例子,“jupiter”主机完整的域名是“https://www.wendangku.net/doc/ae8031830.html,”。换句话说,“jupiter”系统是“catalyst”域名(一个公司的本地网络)的一部分,而这个域名又是“com”域名(一个用于所有商业公司的域名)。

为了使用主机名代替点分十进制去指定特定的主机或网络。那么就必须将这两者相关起来。有一两个办法可以做到:一个本地主机或者一个名字服务器。一个主机表格是一个文本文件,它列出了IP地址和它对应的紧跟其后的被熟知的主机的名字。这个文件通常被叫做hosts,它可以在安装了TCP/IP软件的目录中找到。另一方面,一个名字服务器是一个可以将主机名以它对应的IP的地址呈现并返回的系统。这种方法的好处是整个网络的主机信息被特定的本地服务器维护而不是被分散在网络中的所有主机。

1.4 服务端口

添加了远程系统的主机IP地址,一个应用程序还需要知道如何定位它想要通信的特定的程序。这个同个一个16位的特定的服务端口号来指明,这个端口号可以指定系统上一个特定的应用程序。但是通常使用的是服务名来代替端口号,服务名通常使用称作“cervices”的本地文件与端口号匹配,这个文件列出了本地服务的名称,还有端口号以及服务使用的协议。

一个基础的服务名的端口号常常被基于以太网的应用程序使用并且被称作知名服务,这些服务被定义在标准文档中包括普通的应用协议,比如FTP,POP3,SMTP 和HTTP。

一个服务名或者一个端口号是为了标识一个主机中的正在运行的应用程序。因为一个特定的服务名已经被使用,她不能保证服务一定是可用的,就好像拨打一个电话号码并不能保证这个人一定在家并且回复这个呼叫。

1.5套接字

之前的部分描述了一个应用程序在TCP/IP网络上通行所需要的信息。下一步是创建一个叫做套接字的程序,一个通信端结点可以使用电话线连接。无论怎样,创建一个套接字并不能让你交换信息,就好像有了一个电话在家里并且简单的插上了电话线,并不意味这你可以和别人讲话。你需要与另一个程序建立一个连接,就像是你需要拨一个电话号码,为了做到这点你需要你所想要连接的程序的套接字地址。这个地址包括三个重要的成分:协议家族,IP地址还有服务端口号

我们已经讨论了IP地址和服务端口号,但是什么是协议家族呢?它是一个号码,用来逻辑上指明使用的协议属于哪一个组。因为套接字是一个普遍应用于不同协议的接口,协议家族告诉下层的网络软件哪个协议正在被套接字使用。另一方面创建套接字的时候IP协议家族总是被使用。使用这个协议家族,还有你想要交换信息的系统的IP地址和程序的服务端口号,这样就做好了所有建立连接的准备

1.6客户机-服务器应用程序

开发TCP程序使用了客户机-服务器模型。如先前提到的,当两个软件想要通过TCP交换数据时,一个程序扮演客户机的角色,另一个程序扮演服务器的角色。客户机应用程序一一种称为主动打开的方式开始建立连接,它创建一个套接字主

动向服务器发出请求,服务器此时正在执行一个被称为被动打开的过程。当客户机开始建立连接,服务器被通知有进程想要和它建立连接,服务器即可通过接受请求完成虚电路的建立,虚电路是一个两个程序之间的通信通道,接受连接创建新的套接字是重要的,因为先前用于监听的套接字还要继续监听连接请求,所以不能被改变,当服务器不想在监听新的连接是,他将关闭先前的被动套接字。

复习一下,使用TCP编程建立并且完成一个连接有五个步骤:服务器放完成这些:

1.建立套接字

2.监听收到的来自客户机的连接请求。

3.接受客户机的连接。

4.发送接受信息

5.当结束是关闭套接字,终结会话

在客户机放,要执行如下步骤:

1.创建套接字

2.指出服务程序的地址和服务端口号。

3.与服务器建立连接

4.发送接受信息

5.当结束是关闭套接字,终结会话

依据它们是客户机还是服务器,只有第二三步是不同

1.7阻塞套接字与非阻塞套接字比较

当你使用windows套接字开发应用程序是你首先会遭遇到一个棘手的问题:阻塞套接字与非阻塞套接字的区别。无论何时你想在套接字上执行操作是,它都不会立即完成并且想你的程序返回信息。举个例子,在套接字上读不可能在远程主机已经发送了数据之前完成。如果在套接字没有数据等待被读,它可以立即返回一个错误指明那里没有数据可以被读。

第一个例子叫做阻塞套接字。程序将被阻塞直到数据请求被完成。当远程系统在套接字上写数据时,读操作完成后程序的执行将会重新开始。第二种情况称为非阻塞套接字,要求应用程序认识错误状态,并且对这种状况进行适当的处理。使用非阻塞套接字的程序在发生数据时通常使用这样的方法:第一种:轮询,使用一个计时器周期性的尝试在套接字上进行读写数据。第二种:推荐的方法,异步通知。使用这种方法时当有任何套接字事件发生时程序会得到通知,并且会回应这个事件。举个例子,如果远程的程序写某个数据,一个读时间就会产生,程序就知道它可以在那个端口的套接字接受数据。

因为历史的原因,套接字函数默认的行为是阻塞的,它会直到操作结束才返回。但是阻塞套接字在windows中会引起一些特殊的问题,比如在16位的应用程序

中,阻塞函数将会进入一个消息循环,在这个循环中应用Windows和其他的应用程序不断的发送消息。这点消息被处理,就意味着程序会因为在程序堆栈中的阻塞操作而在不同点位再次进入。例如,当按下一个按钮,程序会从套接字中尝试读取一些数据。因为还没有数据被写入,程序被阻塞并进入一个消息环。后来用户又按下了另一个按钮,这个按钮使代码被执行,使得程序从套接字中读取数据,还有一些这类的问题。

阻塞套接字在32位应用程序中会带来另外的问题,因为阻塞函数会阻止访问线程处理向它发送的任何消息。然而许多应用程序都是单线程的,这可能会导致应用程序对用户的操作没有响应。为了解决阻塞套接字带来的一般性问题,Windows套接字标准声明在每个线程执行时只能有一个阻塞调用。这意味着16位的应用程序发生再次进入将会产生错误,因为无论什么时候它们试图产生动作阻塞函数都已经运行。对于32位程序,工作线程的产生是解决阻塞套接字操作的共同方法,虽然它为应用程序带来了更多的复杂性。

SocketWrench控件使用非阻塞式套接字响应事件。例如,远程主机向套接字中写入数据时,就创建一个读事件,它告诉你的应用程序那里有数据需要读取。非阻塞式套接字的用途在接下来的部分会得到验证。控件相对于Windows套接字接口的明显的优点是它最关键的部分之一。

总的来说,关于通过控制阻塞和非阻塞套接字创建一个应用程序有三种通用的方法:

使用阻塞套接字(同步).使用这种方法,程序会等到套接字操作完成后才会继续执行。16位应用程序的阻塞套接字会允许在不同点重复进入,32位应用程序会停止响应用户的操作。如果应用程序使用多重操作,将会导致复杂的交互(和困难的调试)。

使用非阻塞套接字(异步),这会允许你的程序响应事件。例如,当远程系统想套接字中写入数据,一个用以控制的读事件会被创建。你的应用程序会读取套接字中的数据,而且根据收到数据的环境有可能会发送回去一些数据。

使用阻塞和非阻塞混合的套接字操作。这种在阻塞和非阻塞模式之间转换的能力联机提供了一个强大而方便的方式来执行套接字操作。

如果你决定在你的应用程序中使用非阻塞套接字,你一定要检查每次读写操作返回的数据,这一点一定要牢记。因为你有可能并没有发送或接收到所有要求的数据。开发者们经常遇到这样的问题,他们编写了一个程序,并自认为这个程序能够向套接字中读写大量比特。在多数情况下,程序在一个局域网中开发和测试,并想期望的那样正常那样工作,但是当程序被交给一个拥有低速网络连接的用户时,却会有意想不到的失败(比如通过拨号连接到因特网)。在忽略网络的配置和速度的情况下,经常检查这些操作的返回值,你就能够确保你的程序正常的工作。

相关文档