Beej的网络编程指南–什么是socket(第二章)

发布时间:2009/05/25      类别:网络 | 所属专题:

可能您经常听到人们谈论”sockets”,但或许还不是很清楚的知道它到底是个什么。其实:它是使用标准的unix文件描述符与其它程序通讯的一种方式。

什么?

好了,你可能听过unix hacker说过“unix里面任何东西都是文件”,这是实:unix程序无论做任何形式的IO操作其实都是对文件描述符进行读或写。文件描述符是一个同已打开的某一文件相关联的一个整数。而且(注意),这里说的文件可以是一个网络连接,FIFO,管道,终端,硬盘上实实在在的一个文件或者其它任何东西。unix世界中的一切都是文件!所以,当您想通过网络与其他程序交流时,您只需使用文件描述符就可以了。

可能您会想,“我怎么才能得到这种文件描述符呢?”。马上回答您:调用socket()这个系统调用,它会返回一个socket描述符,然后通过send()和recv()完成与其它程序的通讯。

问题又来了,你可能会想“既然都是文件描述符,那为什么我们不使用read()和write()这两个系统调来读写刚才获取到的socket描述符呢?”,事实上您确实可以使用他们,但send()和recv()可以更好的控制数据的传送。

继续,现实中存在多种socket,比如使用DARPA Internet addresses的DARPA sockets, 使用文件路径名为地址的unix domain socket, 使用CCITT X.25 addresses的X.25 socket(这个您可以放心的跳过),可能还有其它的一些socket。本文只关注:Internet Sockets,即tcp/ip socket.

2.1. 两种 Internet Sockets

什么?还有两种Internet sockets?是的,不,说笑呢。其实不止两种,但又怕吓到您而不敢继续了。本文只讲使用最为广泛的两种。不过要告诉您的是还有一种raw socket也很好很强大,需要您自己查阅相关资料哦。

好了,本文要讲的是哪两种Internet socket呢?Stream Sockets(流式socket)和Datagram Sockets(数据报socket),即以后经常提及的SOCK_STREAM和SOCK_DGRAM。数据报socket有时也叫无连接的socket(虽然您可以使用connect()调用来连接).

流式sockets 是可靠的双工数据流。如果您向这种socket顺序写入1,2两个数据,那么它们也会按顺序到达接收方,而且数据也是不会在传输过程中发生错误或丢失,这点大家可以放心。

什么时候使用流socket呢?您应该听说过telnet这个程序吧?它就使用了流式socket。输入的所有字符您都希望按顺序到达另一端的主机,对吧!还有网页浏览器同样也使用流式socket来获取网页。事实上,您用telnet登陆到一个网站主机的80号端口,输入”GET / HTTP/1.0″,然后按两次回车,看到什么了,HTML网页源代码!

流式socket是怎么得到这种高质量的数据传输的呢?原因在于流式socket使用了“传输控制协议”,即TCP(The Transmission Control Protocol,详见RFC 793)。TCP协议保证您的数据会有序可靠地到达通信的另一端。也许您听得更多的是TCP/IP,这里的IP指的是”Internet Protocol” (详见 RFC 791)。IP协议负责路由,它并不保证数据的完整性,这就是分工协作。

嗯,不错。那数据报socket呢?为什么会说它是无连接的?为什么它不可靠?这些又有什么关系呢?简单说来:如果您发送一堆数据出去,可能这些数据能够到达对方,也可能在路途中丢失了,也可能到了对方顺序却乱了,还可能数据本身都已经出错了,对方得到的数据已经面目全非了。数据报socket同样使用IP路由,但不使用TCP而是使用UDP(User Datagram Protocol,详见RFC 768)。至于为什么说它是无连接的,答案是,您不必像流式socket那样为了与对方通信而始终保持一个连接。在这种数据报socket中,您只需打好一个数据报,然后发送即可,无需连接。通常这种socket用于丢失少量数据或则乱序而不会影响很大的场合。使用数据报socket的应用主要有:tftp, dhcpcd, 多人游戏,音视频数据传输等。

“等等,tftp和dhcpcd传输的数据都不能乱序的,也不能丢失,为什么还使用数据报socket呢?有什么玄妙么?”。问题在于这些程序在UDP协议之上建立了自己的协议来负责处理数据丢失的问题。比如,tftp协议在发送了一个数据报后会等待对方的回应,如果在一段时间内没有得到回应,则会重发数据。这种回应机制对于创建使用SOCK_DGRAM socket而又想得到可靠性的应用程序是非常重要的。

对于其它的不是特别在乎可靠性的应用程序来说,比如游戏,音视频数据,您不用管那些已经丢失了的数据,或则您可以做一些补救。如Quake玩家熟悉的术语:卡。

既然有可靠地协议,为什么我们还要使用那些不可靠的协议呢?两个原因:速度,还是速度!不可靠的协议不需要检查数据是否完整,是否乱序,也不需要得到tcp ack那种确认,所以它的速度要比tcp快一些。如果您要发送聊天数据,TCP最好用,但如果您要在网络游戏中发送某某人的动作或则坐标,好像丢一两个数据包无关紧要吧,这时UDP派上了用场。

2.2. 网络基础理论

刚才提到了网络协议分层,现在我们来看看低层的网络到底是如何工作的,同时也会举一些例子来描述SOCK_DGRAM包是如何构建的。虽然本节描述的是网络编程很好的背景知识,但您也可以放心的跳过这些内容继续后面的学习。

现在我们来学习数据封装!这点知识非常重要,重要到就像小学学习一加一等于二那样您必须掌握。我们以使用udp协议的应用程序为例来介绍,封装过程如下:应用程序首先产生一个用户数据包,然后通过send()系统调用把这个包交给udp协议层,udp协议层得到这个包后就在这个包的前面加上自己的Udp协议头,然后把这一整块数据(udp协议头和您的数据)交给下一个协议如IP协议包装,之后再交给数据链路层并用该层的协议包装起来,最后就通过电缆或其他通信介质把这一大块经过包装后的数据发送出去。

另一端的网卡收到数据后,首先把数据链路层的协议头去掉,然后交给ip层,ip层去掉ip头后交给udp协议层,udp协议层去掉udp头后交给应用程序。

下面我来介绍一下著名的ISO/OSI网络协议分层模型。这种网络模型较其他相应模型具有更多的优点。如,您可以轻易写一个socket网络程序而不用担心数据到底是如何通过各种不同的网络(以太网,串口或是其它介质的网络)传送到另一端的,因为低层的协议为您做了这些工作。低层的物理网络硬件和拓扑结构对于网络程序员来说是透明的。
废话少说,下面列出这个模型的所有分层,如果您要参加考试,可一定要记住哦:

应用层 (Application)
表示层 (Presentation)
会话层 (Session)
传输层(Transport)
网络层(Network)
数据链路层(Data Link)
物理层(Physical)

物理层是网络硬件(串口,以太网等).. 应用层离物理层最远,它是用户与网络交互的地方。

这个网络分层模型使用非常广泛,它也是TCP/IP分层模型的基础,TCP/IP各层如下:

应用层(Application Layer) (telnet, ftp等)
传输层(Host-to-Host Transport Layer) (TCP, UDP)
网络层(Internet Layer) (IP和路由)
网络访问层 (Network Access Layer) (以太网,wi-fi网,或则其它)

到此,您应该对前面我们讲的数据封装有了更好的认识了吧,每次封装都对应着这里的某一层。

构建一个简单的网络数据包难道要做上面说述的那么工作吗?非也,作为程序员的您您只需把您想要发送的数据交给send()或sendto()即可,操作系统内核会自动为您做打包的工作,啊哈,高科技!

好了,网络基础知识我们就讨论这些了。哦,忘了件事告诉您–路由:但事实上作为一个socket程序员,我们并不需要关心它,所以在这里我也不打算讨论它,当然如果您能够掌握路由知识也是大有裨益的,所以如果您真有兴趣的话,请参考ip相关的RFC文档。当然,如果您不学它,您也会活得很好!

发表评论