网络通讯.docx
- 文档编号:24479450
- 上传时间:2023-05-27
- 格式:DOCX
- 页数:31
- 大小:213.69KB
网络通讯.docx
《网络通讯.docx》由会员分享,可在线阅读,更多相关《网络通讯.docx(31页珍藏版)》请在冰豆网上搜索。
网络通讯
Linux下网络编程
网络程序设计全靠套接字接受和发送信息,尽管套接字这个词好象显得有些神秘,但其实这个概念极易理解。
一、Socket的历史
在80年代早期,远景研究规划局(AdvancedResearchProjectsAgency,ARPA)资助了佳利福尼亚大学伯克利分校的一个研究组,让他们将TCP/IP软件移植到UNIX操作系统中,并将结果提供给其他网点。
作为项目的一部分,设计者们创建了一个接口,应用进程使用这个接口可以方便的进行通信。
他们决定,只要有可能就使用以有的系统调用,对那些不能方便的容入已有的函数集的情况,就再增加新的系统调用以支持TCP/IP功能。
这样做的结果就出现了插口接口(BerkeleySocket),这个系统被称为BerkeleyUNIX或BSDUNIX。
(TCP/IP首次出现在BSD4.1版本release4.1ofBerkeleySoftwareDistribution)。
由许多计算机厂商,都采用了BerkeleyUNIX,于是许多机器上都可以使用Socket了。
这样,Socket接口就被广泛使用,到现在已经成为事实上的标准。
socket接口工作示意图
Socket实质上提供了进程通信的端点。
进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。
正如打电话之前,双方必须各自拥有一台电话机一样。
每一个Socket都用一个半相关描述:
{协议,本地地址,本地端口}
一个完整的Socket则用一个相关描述
{协议,本地地址,本地端口,远程地址,远程端口}
每一个Socket有一个本地的唯一Socket号,由操作系统分配。
最重要的是,Socket是面向客户-服务器模型而设计的,针对客户和服务器程序提供不同的Socket系统调用。
客户随机申请一个Socket号(相当于一个想打电话的人可以在任何一台入网的电话上拨叫呼叫);服务器拥有全局公认的Socket,任何客户都可以向它发出连接请求和信息请求(相当于一个被呼叫的电话拥有一个呼叫方知道的电话号码)。
Socket利用客户—服务器模式巧妙的解决了进程之间建立通信连接的问题。
服务器Socket为全局所公认非常重要。
两个完全随机的用户进程之间,因为没有任何一方的Socket是固定的,就像打电话却不知道别人的电话号码,要通话是不可能的。
二、套接字的三种类型
套接字有三种类型:
流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)及原始套接字。
1.流式套接字(SOCK_STREAM)
流式的套接字可以提供可靠的、面向连接的通讯流。
如果你通过流式套接字发送了顺序的数据:
“1”、“2”。
那么数据到达远程时候的顺序也是“1”、“2”。
流式套接字是怎样保证这种应用层次上的数据传输质量呢?
它使用了TCP(TheTransmissionControlProtocol)协议(可以参考RFC-793来得到TCP的细节)。
TCP保证了你的数据传输是正确的,并且是顺序的。
TCP是经常出现的TCP/IP中的前半部分。
IP代表InternetProtocol(因特网协议,参考RFC-791)IP只处理网络路由。
面向连接的socket的工作流程
套接字工作过程如下:
服务器首先启动,通过调用socket()建立一个套接字,然后调用bind()将该套接字和本地网络地址联系在一起,再调用listen()使套接字做好侦听的准备,并规定它的请求队列的长度,之后就调用accept()来接收连接。
客户在建立套接字后就可调用connect()和服务器建立连接。
连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据。
最后,待数据传送结束后,双方调用close()关闭套接字。
2.数据报套接字(SOCK_DGRAM)
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。
原始套接字允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。
数据报套接字(DatagramSockets)怎样呢?
为什么它叫做“无连接”?
应该怎样处理它们呢?
为什么它们是不可靠的?
好的,这里有一些事实:
●如果你发送了一个数据报,它可能不会到达。
●它可能会以不同的顺序到达。
●如果它到达了,它包含的数据中可能存在错误。
数据报套接字也使用IP,但是它不使用TCP,它使用使用者数据报协议UDP(UserDatagramProtocol可以参考RFC768)
为什么说它们是“无连接”的呢?
因为它(UDP)不像流式套接字那样维护一个打开的连接,你只需要把数据打成一个包,把远程的IP贴上去,然后把这个包发送出去。
这个
过程是不需要建立连接的。
UDP的应用例子有:
tftp,bootp等。
那么,数据包既然会丢失,怎样能保证程序能够正常工作呢?
事实上,每个使用UDP的程序都要有自己的对数据进行确认的协议。
比如,TFTP协议定义了对于每一个发送出去的数据包,远程在接受到之后都要回送一个数据包告诉本地程序:
“我已经拿到了!
”(一个“ACK”包)。
如果数据包发的送者在5秒内没有的得到回应,它就会重新发送这个数据包直到数据包接受者回送了“ACK”信号。
这些知识对编写一个使用UDP协议的程序员来说是非常必要的。
无连接服务器一般都是面向事务处理的,一个请求一个应答就完成了客户程序与服务程序之间的相互作用。
若使用无连接的套接字编程,程序的流程可以用下图表示。
无连接的socket工作流程
3.原始套接字
原始套接字主要用于一些协议的开发,可以进行比较底层的操作。
它功能强大,但是没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。
三、Linux支配的网络协议
网络协议是系统进行系统与系统间通讯的的接口。
在Linux系统上,TCP/IP(TransmissionControl/InternetProtocol)是最常见的。
TCP/IP是一个网络协议协议族,我们将在下面进行详细介绍。
1什么是TCP/IP?
用简单的话来讲,TCP/IP是一个网络协议族的名字,协议是所有软件产品必须遵守的、能够保证各种软件产品能够正确通讯的规则。
协议还定义了每一部分数据块怎样管理所传输的数据。
精确一点说,一个协议定义了两个应用程序或是计算机之间能够进行互相通讯,对于其中的每一个(应用程序或计算机)都保证使用同样的标准。
TCP/IP代表传输控制协议/网络协议(注意:
它们是两个不同的协议!
),它是做为软件的网络组成部件而设计的。
每个TCP/IP的协议都有他专门的工作,比如万维网(WWW),发送电子邮件(E-mail),传输文件(Ftp),提供远程登陆服务等。
TCP/IP协议可以根据提供的不同的服务分为几组:
1.控制数据的协议
TCP(传输控制协议TransmissionControlProtocol)以连接为基础,也就是说两台电脑必须先建立一个连接,然后才能传输数据。
事实上,发送和接受的电脑必须一直互相通讯和联系。
UDP(使用者数据报协议UserDatagramProtocol)它是一个无连接服务,数据可以直接发送而不必在两台电脑之间建立一个网络连接。
它和有连接的TCP相比,占用带宽少,但是你不知道你的数据是否真正到达了你的客户端,而客户端收到的数据也不知道是否还是原来的发送顺序。
2.数据路由协议
路由协议分析数据包的地址并且决定传输数据到目的电脑最佳路线。
他们也可以把大的数据分成几部分,并且在目的地再把他们组合起来。
IP(因特网协议InternetProtocol)处理实际上传输数据。
ICMP(因特网控制信息协议InternetControlMessageProtocol)处理IP的状态信息,比如能影响路由决策的数据错误或改变。
RIP(路由信息协议RoutingInformationProtocol)它是几个决定信息传输的最佳路由路线协议中的一个。
OSPF(OpenShortestPathFirst)一个用来决定路由的协议。
网络地址协议决定了命名电脑地址的方法:
使用一个唯一的数字和一个字母名字。
ARP(地址决定协议AddressResolutionProtocol)确定网络上一台电脑的数字地址。
DNS(域名系统DomainNameSystem)从机器的名字确定一个机器的数字地址。
RARP(反向地址决定协议ReverseAddressResolutionProtocol)确定网络上一台计算机的地址,和ARP(地址决定协议AddressResolutionProtocol)正好相反。
3.用户服务
BOOTP(启动协议BootProtocol)由网络服务器上取得启动信息,然后将本地的网络计算机启动。
FTP(文件传输协议FileTransferProtocol)通过国际互连网从一台计算机上传输一个或多个文件到另外一台计算机。
TELNET(远程登陆)允许一个远程登陆,使用者可以从网络上的一台机器通过TELNET连线到另一台机器,就像使用者直接在本地操作一样。
EGP(外部网关协议ExteriorGatewayProtocol)为外部网络传输路由信息。
GGP(网关到网关协议Gateway-to-GatewayProtocol)在网关和网关之间传输路由协议。
IGP(内部网关协议InteriorGatewayProtocol)在内部网络传输路由信息。
4.其他协议(也为网络提供了重要的服务)
NFS(网络文件系统NetworkFileSystem)允许将一台机器的目录被另一台机器上的用户安装(Mount)到自己的机器上,就像是对本地文件系统进行操作一样进行各式各样的操作。
NIS(网络信息服务NetworkInformationService)对整个网络用户的用户名、密码进行统一管理,简化在NIS服务下整个网络登陆的用户名/密码检查。
RPC(远程过程调用RemoteProcedureCall)通过它可以允许远程的应用程序通过简单的、有效的手段联系本地的应用程序,反之也是。
SMTP(简单邮件传输协议SimpleMailTransferProtocol)一个专门为电子邮件在多台机器中传输的协议,平时发邮件的SMTP服务器提供的必然服务。
SNMP(简单网络管理协议SimpleNetworkManagementProtocol)这是一项为超级用户准备的服务,超级用户可以通过它来进行简单的网络管理。
四、套接字地址
1什么是socket
大家经常谈论“Socket”(套接字),那么一个套接字究竟是什么呢?
一个套接字可以这样来解释:
它是通过标准的UNIX文件描述符和其他的程序通讯的一个方法。
2Socket描述符
使用UNIX的黑客高手有这么一句话:
“恩,在UNIX系统中,任何东西都是一个文件。
”这句话描述了这样一个事实:
在UNIX系统中,任何对I/O的操作,都是通过读或写一个文件描述符来实现的。
一个文件描述符只是一个简单的整形数值,代表一个被打开的文件(这里的文件是广义的文件,并不只代表不同的磁盘文件,它可以代表一个网络上的连接,一个先进先出队列,一个终端显示屏幕,以及其他的一切)。
在UNIX系统中任何东西都是一个文件!
!
所以如果你想通过Internet和另外一个程序通讯的话,你将会是通过一个文件来描述符实现的。
你最好相信这一点。
3一个套接字是怎样在网络上传输数据的?
我们已经谈过了网络协议层,那么我们还应该继续多了解一些东西:
物理网络上的数据是怎样传送的。
我们可以认为是这样的:
OSI参考模型中的数据封装过程
数据被分成一个一个的包(Packet),包的数据头(或数据尾)被第一层协议(比如TFTP协议)加上第一层协议数据;然后整个包(包括内部加入的TFTP信息头)被下层协议再次包装(比如UDP),再这之后数据包会再次被下层协议包装(比如IP协议),最后是被最底层的硬件层(物理层)包装上最后一层信息(Ethernet信息头)。
当接受端的计算机接收到这个包后,硬件首先剥去数据包中的Ethernet信息头,然后内核在剥去IP和UDP信息头,最后把数据包提交给TFTP应用程序,由TFTP剥去TFTP信息头,最后得到了原始数据。
下面我们再大致回顾一下著名的网络层次模型。
通过这个网络模型,你可以写套接字的应用程序而不必在乎事实上数据在物理层中的传输方法(无论是以太网,还是并口、AUI或是其他的什么方法)。
因为已经有程序在底层为你处理了这些问题了。
下面是OSI模型,你可以记住它来应付一些测验。
OSI参考模型
(1)应用层:
与其他计算机进行通讯的一个应用,它是对应应用程序的通信服务的。
例如,一个没有通信功能的文件处理程序就不能执行通信的代码,从事文件处理工作的程序员也不关心OSI的第7层。
但是,如果添加了一个传输文件的选项,那么文件处理程序的程序员就需要实现OSI的第7层。
示例:
telnet,HTTP,FTP,WWW,NFS,SMTP等。
(2)表示层:
这一层的主要功能是定义数据格式及加密。
例如,FTP允许你选择以二进制或ASII格式传输。
如果选择二进制,那么发送方和接收方不改变文件的内容。
如果选择ASII格式,发送方将把文本从发送方的字符集转换成标准的ASII后发送数据。
在接收方将标准的ASII转换成接收方计算机的字符集。
示例:
加密,ASII等。
(3)会话层:
他定义了如何开始、控制和结束一个会话,包括对多个双向小时的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的,在某些情况下,如果表示层收到了所有的数据,则用数据代表表示层。
示例:
RPC,SQL等。
(4)传输层:
这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。
示例:
TCP,UDP,SPX。
(5)网络层:
这层对端到端的包传输进行定义,他定义了能够标识所有结点的逻辑地址,还定义了路由实现的方式和学习的方式。
为了适应最大传输单元长度小于包长度的传输介质,网络层还定义了如何将一个包分解成更小的包的分段方法。
示例:
IP,IPX等。
(6)数据链路层:
他定义了在单个链路上如何传输数据。
这些协议与被讨论的歌种介质有关。
示例:
ATM,FDDI等。
(7)物理层:
OSI的物理层规范是有关传输介质的特性标准,这些规范通常也参考了其他组织制定的标准。
连接头、针、针的使用、电流、电流、编码及光调制等都属于各种物理层规范中的内容。
物理层常用多个规范完成对所有细节的定义。
示例:
Rj45,802.3等。
物理层就是硬件层(比如并口,以太网)。
应用程序层离物理层很远很远,以至于它
可以不受物理层的影响。
上面这个模型是最一般的模型,但是在Linux中,真正用到的模型是下面这样子的:
●应用层(Telnet,Ftp,等等)
●主机间对话层(TCP和UDP)
●网络层(IP和路由)
●网络底层(相当于OSI模型中网络、数据链路和物理层)
OSI参考模型VSTCP/IP参考模型
*应用层——应用层是所有用户所面向的应用程序的统称。
ICP/IP协议族在这一层面有着很多协议来支持不同的应用,许多大家所熟悉的基于Internet的应用的实现就离不开这些协议。
如我们进行万维网(WWW)访问用到了HTTP协议、文件传输用FTP协议、电子邮件发送用SMTP、域名的解析用DNS协议、远程登录用Telnet协议等等,都是属于TCP/IP应用层的;就用户而言,看到的是由一个个软件所构筑的大多为图形化的操作界面,而实际后台运行的便是上述协议。
*传输层——这一层的的功能主要是提供应用程序间的通信,TCP/IP协议族在这一层的协议有TCP和UDP。
*网络层——是TCP/IP协议族中非常关键的一层,主要定义了IP地址格式,从而能够使得不同应用类型的数据在Internet上通畅地传输,IP协议就是一个网络层协议。
*网络接口层——这是TCP/IP软件的最低层,负责接收IP数据包并通过网络发送之,或者从网络上接收物理帧,抽出IP数据报,交给IP层。
现在,你大概已经明白各个协议层是怎样对原始数据进行包装和解包的了吧。
对流式套接字你所需要做的只是调用send()函数来发送数据。
而对于数据报套接字,你需要自己加个信息头,然后调用sendto()函数把数据发送出去。
Linux系统内核中已经建立了TransportLayer和InternetLayer。
硬件负责NetworkAccessLayer。
简单而有效,不是吗?
五、套接字的一些基本知识
一、基本结构
首先,介绍一些使用套接字编程中常见的网络数据结构。
1.structsockaddr
这个结构用来存储套接字地址。
数据定义:
structsockaddr{
unsignedshortsa_family;/*address族,AF_xxx*/
charsa_data[14];/*14bytes的协议地址*/
};
sa_family通信协议的协议族,对于TCP/IP协议族,一般来说,都是“AF_INET”。
sa_data包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一切的。
为了处理structsockaddr,程序员建立了另外一个相似的结构structsockaddr_in:
structsockaddr_in(“in”代表“Internet”)
structsockaddr_in{
shortintsin_family;/*Internet地址族*/
unsignedshortintsin_port;/*端口号*/
structin_addrsin_addr;/*Internet地址*/
unsignedcharsin_zero[8];/*添0(和structsockaddr一样大小)*/
};
这个结构提供了方便的手段来访问socketaddress(structsockaddr)结构中的每一个元素。
注意sin_zero[8]是为了是两个结构在内存中具有相同的尺寸,使用sockaddr_in的时候要把sin_zero全部设成零值(使用bzero()或memset()函数)。
而且,有一点很重要,就是一个指向structsockaddr_in的指针可以声明指向一个sturctsockaddr的结构。
所以虽然socket()函数需要一个structaddr*,你也可以给他一个sockaddr_in*。
注意在structsockaddr_in中,sin_family相当于在structsockaddr中的sa_family,需要设成“AF_INET”。
最后一定要保证sin_port和sin_addr必须是网络字节顺序
2.structin_addr
其定义如下:
/*因特网地址(astructureforhistoricalreasons)*/
structin_addr{
unsignedlongs_addr;
};
如果你声明了一个“ina”作为一个structsockaddr_in的结构,那么“ina.sin_addr.s_addr”就是4个字节的IP地址(按网络字节顺序排放)。
需要注意的是,即使你的系统仍然使用联合而不是结构来表示structin_addr,你仍然可以用上面的方法得到4个字节的IP地址(一些#define函数帮了你的忙)。
2基本转换函数
在前面提到了网络字节顺序。
那么什么是网络字节顺序,它有什么特殊性,又如何将我们通常使用的数据转换成这种格式呢?
1.网络字节顺序
因为每一个机器内部对变量的字节存储顺序不同(有的系统是高位在前,底位在后,而有的系统是底位在前,高位在后),而网络传输的数据大家是一定要统一顺序的。
所以对与内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换(比如IP地址的表示,端口号的表示)。
但是内部字节顺序和网络字节顺序相同的机器该怎么办呢?
是这样的:
它们也要调用转换函数,但是真正转换还是不转换是由系统函数自己来决定的。
2.有关的转化函数
我们通常使用的有两种数据类型:
短型(两个字节)和长型(四个字节)。
下面介绍的这些转换函数对于这两类的无符号整型变量都可以进行正确的转换。
如果你想将一个短型数据从主机字节顺序转换到网络字节顺序的话,有这样一个函数:
它是以“h”开头的(代表“主机”);紧跟着它的是“to”,代表“转换到”;然后是“n”代表“网络”;最后是“s”,代表“短型数据”。
H-to-n-s,就是htons()函数(可以使用HosttoNetworkShort来助记)
下面给出套接字字节转换程序的列表:
●htons()——“HosttoNetworkShort”主机字节顺序转换为网络字节顺序(对无符号短型进行操作4bytes)
●htonl()——“HosttoNetworkLong” 主机字节顺序转换为网络字节顺序(对无符号长型进行操作8bytes)
●ntohs()——“NetworktoHostShort“ 网络字节顺序转换为主机字节顺序(对无符号短型进行操作4bytes)
●ntohl()——“NetworktoHostLong“ 网络字节顺序转换为主机字节顺序(对无符号长型进行操作8bytes)
3.IP地址转换
很幸运,Linux系统提供和很多用于转换IP地址的函数,使你不必自己再写出一段费力不讨好的子程序来吃力的变换IP。
首先,让我假设你有一个structsockaddr_inina,并且你的IP是166.111.69.52,你想把你的IP存储到ina中。
你可以使用的函数:
inet_addr(),它能够把一个用数字和点表示IP地址的字符串转换成一个无符号长整型。
你可以像下面这样使用它:
ina.sin_addr.s_addr=inet_addr(“166.111.69.52”);
现在我们已经可以把字符串的IP地址转换成长整型了。
那么还有没有其他的方法呢?
如果你有一个structin_addr并且你想把它代表的IP地址打印出来(按照数字.数字.数字.数字的格式)⋯⋯
这里,你可以使用函数inet_ntoa()(“ntoa”代表“NetworktoASCII”):
printf(“%s”,inet_ntoa(ina.sin_addr));
这段代码将会把structin_addr里面存储的网络地址以数字.数字.数字.数字的格式显示出来。
六、基本套接字调用
Linux支持伯克利(BSD)风格的套接字编程.它同时支持面向连接和不连接类型的套接字。
在面向连接的通讯中服务器和客户机在交换数据之前先要建立一个连接.再不连接通讯中数据被作为信息的一部分被交换.无论那一种方式,服务器总是最先启动,把自己绑定(Banding)在一个套接字上,然后侦听信息.服务器究竟怎样试图去侦听就得
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 网络通讯