Linux_Unix网络编程指南(Socket 编程)

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

Linux/Unix网络编程指南(Socket编程)什么是socket?你始终听到人们谈论着socket,而你不知道他的确切含义。那么,现在我告诉你:他是使用Unix文件描述符(filedescriptor)和其他程序通讯的方式。什么?Ok--你也许听到一些Unix高手(hacker)这样说:“Unix中所有的东西就是文件!”那个家伙也许正在说到一个事实:Unix程序在执行任何形式的I/O的时候,程序是在读或者写一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数。但是(注意后面的话),这个文件可能是一个网络连接,FIFO,管道,终端,磁盘上的文件或者什么其他的东西。Unix中所有的东西是文件!因此,你想和Internet上别的程序通讯的时候,你将要通过文件描述符。最好相信刚才的话。现在你脑海中或许冒出这样的念头:“那么我从哪里得到网络通讯的文件描述符呢,聪明人?”无论如何,我要回答这个问题:你利用系统调用socket()。他返回套接口描述符(socketdescriptor),然后你再通过他来调用send()和recv()。“但是...”,你可能现在叫起来,“如果他是个文件描述符,那么为什么不用一般的调用read()和write()来通过套接口通讯?”简单的答案是:“你可以使用一般的函数!”。详细的答案是:“你可以,但是使用send()和recv()让你更好的控制数据传输。”有这样一个事实:在我们的世界上,有很多种套接口。有DARPAInternet地址(Internet套接口),本地节点的路径名(Unix套接口),CCITTX.25地址(你可以完全忽略X.25套接口)。也许在你的Unix机器上还有其他的。我们在这里只讲第一种:Internet套接口。--------------------------------------------------------------------------------Internet套接口的两种类型什么意思?有两种Internet套接口?是的。不,我在撒谎。其实还有很多,但是我可不想吓着你。我们这里只讲两种。Exceptforthissentence,whereI'mgoingtotellyouthatRawSocketsarealsoverypowerfulandyoushouldlookthemup.那两种类型是什么呢?一种是StreamSockets,另外一种是DatagramSockets。我们以后谈到他们的时候也会用到SOCK_STREAM和SOCK_DGRAM。数据报套接口有时也叫“无连接套接口”,如果你确实要连接的时候用connect()。流式套接口是可靠的双向通讯的数据流。如果你向套接口按照顺序输出“1,2”,那么他们将按照顺序“1,2”到达另一边。他们也是无错误的传递的,有自己的错误控制。有谁在使用流式套接口?你可能听说过telnet,不是吗?他就使用流式套接口。你需要你所输入的字符按顺序到达,不是吗?同样,协议也使用他们。实际上,当你通过端口80端口telnet到一个站点,然后输入“GETpagename”的时候,你也可以得到HTML的内容。为什么流式套接口可以达到高质量的数据传输?他使用了“传输控制协议(TheTransmissionControlProtocol)”,也叫“TCP”(请参考RFC-793获得详细资料。)TCP控制你的数据按顺序到达并且没有错误。你也许听到“TCP”是因为听到过“TCP/IP”。这里的IP是指“Internet协议”(请参考RFC-791.)IP只是处理Internet路由而已。那么数据报套接口呢?为什么他叫无连接呢?为什么他是不可靠的呢?恩,有这样的事实:如果你发送一个数据报,他可能到达,他可能次序颠倒了。如果他到达,那么在这个包的内部是无错误的。数据报也使用IP作路由,但是他不选择TCP。他使用“用户数据报协议(UserDatagramProtocol)”,也叫“UDP”(请参考RFC-768.)为什么他们是无连接的呢?主要原因是因为他并不象流式套接口那样维持一个连接。你只要建立一个包,在目标信息中构造一个IP头,然后发出去。不需要连接。应用程序有:tftp,bootp等等。“够了!”你也许会想,“如果数据丢失了这些程序如何正常工作?”我的朋友,每个程序在UDP上有自己的协议。例如,tftp协议每发出一个包,收到者发回一个包来说“我收到了!”(一个“命令正确应答”也叫“ACK”包)。如果在一定时间内(例如5秒),发送方没有收到应答,他将重新发送,直到得到ACK。这一点在实现SOCK_DGRAM应用程序的时候非常重要。--------------------------------------------------------------------------------网络理论既然我刚才提到了协议层,那么现在是讨论网络究竟如何工作和演示SOCK_DGRAM的工作。当然,你也可以跳过这一段,如果你认为已经熟悉的话。朋友们,现在是学习数据封装(DataEncapsulation)的时候了!这非常非常重要。It'ssoimportantthatyoumightjustlearnaboutitifyoutakethenetworkscoursehereatChicoState;-).主要的内容是:一个包,先是被第一个协议(在这里是TFTP)包装(“封装”),然后,整个数据(包括TFTP头)被另外一个协议(在这里是UDP)封装,然后下一个(IP),一直重复下去,直到硬件(物理)层(Ethernet)。当另外一台机器接收到包,硬件先剥去Ethernet头,内核剥去IP和UDP头,TFTP程序再剥去TFTP头,最后得到数据。现在我们终于讲到臭名远播的网络分层模型(LayeredNetworkModel)。这种网络模型在描述网络系统上相对其他模型有很多优点。例如,你可以写一个套接口程序而不用关心数据的物理传输(串行口,以太网,连接单元接口(AUI)还是其他介质。因为底层的程序为你处理他们。实际的网络硬件和拓扑对于程序员来说是透明的。不说其他废话了,我现在列出整个层次模型。如果你要参加网络考试,可一定要记住:应用层(Application)表示层(Presentation)会话层(Session)传输层(Transport)网络层(Network)数据链路层(DataLink)物理层(Physical)物理层是硬件(串口,以太网等等)。应用层是和硬件层相隔最远的--他是用户和网络交互的地方。这个模型如此通用,如果你想,你可以把他作为修车指南。把他应用到Unix,结果是:应用层(ApplicationLayer)(telnet,ftp,等等)传输层(Host-to-HostTransportLayer)(TCP,UDP)Internet层(InternetLayer)(IP和路由)网络访问层(NetworkAccessLayer)(网络层,数据链路层和物理层)现在,你可能看到这些层次如何协调来封装原始的数据了。看看建立一个简单的数据包有多少工作?哎呀,你将不得不使用cat来完成他们!简直是笑话。对于流式套接口你要作的是send()发送数据。对于数据报式套接口你按照你选择的方式封装数据然后用sendto()。内核将为你建立传输层和Internet层,硬件完成网络访问层。这就是现代科技。现在结束我们的网络理论速成班。哦,忘记告诉你关于路由的事情了。但是我不准备谈他。如果你真的想知道,那么参考IPRFC。如果你从来不曾了解他,也没有关系,你还活着不是吗。--------------------------------------------------------------------------------structs终于到达这里了,终于谈到编程了。在这章,我将谈到被套接口用到的各种数据类型。因为他们中的一些太重要了。首先是简单的一个:socketdescriptor。他是下面的类型:int。仅仅是一个常见的int。从现在起,事情变得不可思议了。请跟我一起忍受苦恼吧。注意这样的事实:有两种字节排列顺序:重要的字节在前面(有时叫octet),或者不重要的字节在前面。前一种叫“网络字节顺序(NetworkByteOrder)”。有些机器在内部是按照这个顺序储存数据,而另外一些则不然。当我说某数据必须按照NBO顺序,那么你要调用函数(例如htons())来将他从本机字节顺序(HostByteOrder)转换过来。如果我没有提到NBO,那么就让他是本机字节顺序吧。我的第一个结构(TM)--structsockaddr.这个数据结构为许多类型的套接口储存套接口地址信息:structsockaddr{unsignedshortsa_family;/*addressfamily,AF_xxx*/charsa_data[14];/*14bytesofprotocoladdress*/};sa_family能够是各种各样的事情,但是在这篇文章中是AF_INET。sa_data为套接口储存目标地址和端口信息。看上去很笨拙,不是吗。为了对付structsockaddr,程序员创造了一个并列的结构:structsockaddr_in(in代表Internet.)structsockaddr_in{shortintsin_family;/*Addressfamily*/unsignedshortintsin_port;/*Portnumber*/structin_addrsin_addr;/*Internetaddress*/unsignedcharsin_zero[8];/*Samesizeasstructsockaddr*/};这个数据结构让可以轻松处理套接口地址的基本元素。注意sin_zero(他被加入到这个结构,并且长度和structsockaddr一样)应该使用函数bzero()或memset()来全部置零。Also,andthisistheimportantbit,apointertoastructsockaddr_incanbecasttoapointertoastructsockaddrandvice-versa.这样的话即使socket()想要的是structsockaddr*,你仍然可以使用structsockaddr_in,andcastitatthelastminute!同时,注意sin_family和structsockaddr中的sa_family一致并能够设置为AF_INET。最后,sin_port和sin_addr必须是网络字节顺序(NetworkByteOrder)!你也许会反对道:但是,怎么让整个数据结构structin_addrsin_addr按照网络字节顺序呢?要知道这个问题的答案,我们就要仔细的看一看这个数据结构:structin_addr,有这样一个联合(unions):/*Internetaddress(astructureforhistoricalreasons)*/structin_addr{unsignedlongs_addr;};他曾经是个最坏的联合,但是现在那些日子过去了。如果你声明ina是数据结构structsockaddr_in的实例,那么ina.sin_addr.s_addr就储存4字节的IP地址(网络字节顺序)。如果你不幸的系统使用的还是恐怖的联合structin_addr,你还是可以放心4字节的IP地址是和上面我说的一样(这是因为#define。)--------------------------------------------------------------------------------ConverttheNatives!我们现在到达下个章节。我们曾经讲了很多网络到本机字节顺序,现在是采取行动的时刻了!你能够转换两种类型:sh

1 / 16
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功