IPv4和IPv6在编程的三菱结构化编程手册上和功能上有什么不同

ipv4与ipv6的区别
ipv4与ipv6的区别是什么,安装Windows 7旗舰版之后在网卡的属性选项里面多了一个Internet协议版本 6(TCP/IPv6)的选项,但好像没有使用
已有1个回答
[编辑专家]
专家星级&:&0.5星
问答堂专家综合评分
问题评分&:&0星
采纳、点赞&:&0星
二次回复率&:&5星
内容为广告/垃圾,我要举报!
特聘专家具有协助内容审核的特权
举报后内容将不能在前台展示
错乱举报会导致该权利被剥夺
选择举报原因×
擅长领域:
参与话题:
& & 简单来说Internet协议版本 6(TCP/IPv6)是Internet协议版本 4(TCP/IPv4)替代产品,Internet协议版本 6(TCP/IPv6)主要是为了解决Internet协议版本 4(TCP/IPv4)在最初的设计中没有考虑到今天全球会有这么多网络设备,导致现在的IP地址不够用,如果使用Internet协议版本 6(TCP/IPv6)就可以不用局域网了,每台设备一个IP地址。Internet协议v4(IPv4)& & Internet协议v4(IPv4)是Internet协议的第四个版本,它是第一个得到广泛部署的版本,和IPv6一起,它们是基于标准的 Internet网络互连方法的核心.IPv4仍然是目前部署最广泛的互联网层协议,IPv4的详细定义可参考IETF发布的RFC 791,它取代了早期定义文档RFC 760.IPv4是一个用于链路层包交换网络的连接协议,如以太网,它以尽力模式运行,因为它不能保证信息能100%传递,也不能保证按正确的顺序传输,更不能避免重复传输.IPv4未包含错误控制和流量控制机制,如果通过数据报头中的校验和方法发现数据被损坏,数据将被抛弃,包括数据完整性在内,均通过上层传输层协议解决,如传输控制协议.IPv4使用32位寻址方法,总共包含个有效地址,IPv4有四种不同的地址类型:A、B、C 和D.IPv4的局限性& & 从上世纪80年代开始,人们就意识到IPv4的地址即将耗尽,这是当初设计时未曾预料到的,这也是引入 有类别网络,创建CIDR寻址的驱动因素,尽管采取了这些措施,IPv4地址的消耗速度仍然让人惊讶,目前有两种较权威的估计,一种预测是2010年,也就是今年,IPv4地址将被用光,另一种预测是2012年才会用光.IPv4地址的耗尽主要原因是Internet用户,使用Internet连接的移动设备,以及连接Internet的ADSLmodem或有线modem的爆炸式增长,迫使我们开发和采用IPv6作为替代解决方案.Internet协议v6(IPv6)& & IPv6也就是著名的IPng,即所谓的下一代IP协议,它是被广泛使用的第二个Internet协议版本,它的设计目标是将IPv4逐渐过渡到IPv6,而不是一下子全部消灭掉IPv4,因此保留了IPv4的兼容性,从IPv4到IPv6的主要变化是:& & 扩展了路由和寻址能力:IPv6将IP地址规模从32位扩大到了128位,支持更多层次的寻址水平,更大的可寻址节点数,以及更简单的地址自动配置;& & 通过给多播地址增加一个“范围”域,多播路由的可扩展性得到了改进;& & 定义了一种新地址类型,叫做“任播地址”,它可以识别节点集,发送到任播地址的数据包可以传递给其中任一节点,在IPv6源路由中使用任播地址允许节点控制通信流的路径;& & 简化了报头格式:有些IPv4报头字段被删除或称为可选部分,减少数据包处理成本,让IPv6报头的带宽成本尽可能低.虽然IPv6地址长度是IPv4的4倍,但IPv6报文的头部长度只有IPv4报文头部长度的2倍;& & 改进了对可选项的支持:改进后IP头可选项经过编码后可更有效地进行转发,对可选项的长度限制也更宽松,为今后引入新的可选项提供了极好的灵活性;& & 服务质量(QoS)功能:增加了数据包标记功能,通过标记知道数据包属于哪个特定的通信流;& & 身份验证和隐私保护能力:IPv6包含了提供身份验证,数据完整性和保密等扩展的定义,虽然是扩展,但它们属于IPv6的基础组件;IPv6由两部分组成,基础的IPv6报头和IPv6扩展头.&IPv6的优点& & 有了巨大的地址空间后,ISP有足够的IP地址分配给客户,甚至每个设备都可以拥有自己的IPv6地址.NAT(网络地址转换)已成为处理IP地址短缺得力的技术,但遗憾的是,许多Internet应用程序在NAT下都不能正常工作,如NFS,DNS和集团会议应有,此外,NAT也是企业对企业直接网络连接的障碍,需要进行复杂的地址转换才能让通信变得可靠,但它的扩展性很差,很容易出现单点故障,显得非常脆弱.& & IPv6地址空间扩展的目标之一是让NAT技术边缘化,改善网络的连通性、可靠性和灵活性.IPv6在Internet上重新建立透明的端到端通信,由于IPv6地址长度较长,显得比较笨重,很多人看到那一长串地址都会头晕.IPv6的第二个主要目标是减少人们管理和配置系统的时间,因为IPv6 可以执行无状态自动配置,结合LAN MAC地址,加上网络路由器提供的前缀(不需要DHCP),可以确保创建一个唯一的IP地址.& & 当然,DHCP仍然有它的用处,如DNS服务器,不过需要支持DHCPv6,IPv6也给两个端点提供了一个中间地带,如SLP(Service locetion Protocol,服务定位协议)协议,这可能使网络管理员的工作变得更加轻松.高带宽多媒体和容错应用是IPv6的第四个主要目标,多媒体应用可以利用多播的优势:可以将一个数据报传输到多个接收者.虽然IPv4也有多播功能,但它们是可选的,不是每个路由器和主机都支持,使用IPv6时,多播是必需的,前面已经提到,IPv6还增加了一种新的服务类型“任播”,与多播类似,任播有一个发送和接收数据包的节点组,当一个数据包发到一个任播组时,只会传输到组中的一个成员,这项新功能特别适合于容错环境,如Web服务器,DNS服务器.& & 另一方面,在IPv6上架设VPN(虚拟私有网络)是支持QoS的,IPv6支持IPv4相同的QoS功能,包括DiffServ标记,以及新的 20位通信流字段,IPv6的第五个主要目标是VPN.新的IPsec安全协议,ESP(封装安全协议)和AH(身份验证头)是附加到IPv4的,而 IPv6内置了这些协议,这意味着在IPv6世界中建设和部署网络时,保护网络的安全将会变得更加容易.以上文章仅为参考帮助说明,并不做全面的可适用性保证,相关支持请点击右侧的微博进行讨论。点击搜索更多硬件问答:更多的关于电脑和网络的问题请到交流分享希望以上信息对你有所帮助
留下你的评论
微信公众账号ZOL问答堂
关注微信,随时随地解答您的疑惑
ZOL问答堂官方微博@ZOL问答堂
关注成功!该问题被回答后,将给您发送站内短信。
您也可以通过关注问答堂微信,及时获得您关注问题的回答。
微信关注问题方法“”ipv4和ipv6的哪个好?ipv4和ipv6的区别对比
作者:佚名
字体:[ ] 来源:互联网 时间:02-02 09:04:18
ipv4和ipv6的哪个好?接下来小编就为大家带来ipv4和ipv6的区别对比,感兴趣的朋友可以看一下
  ipv4和ipv6的区别有哪些?大家可以通过下文来了解ipv4和ipv6的区别,我们在连接无线网络是会出现ipv4和ipv6,那么这两者的区别究竟是哪里呢?想知道的朋友请看下文吧。
  我们大多数人使用的是第二代互联网IPv4技术,它的最大问题是网络地址资源有限,从理论上讲能编址1600万个网络、链接40亿台主机。而根据相关数据,全球IPv4的IP地址已经即将用完。
  而IPv6是作为IETF设计的用于替代现行版本IP协议(IPv4)的下一代IP协议,其IPV6地址长度为128位,地址空间增大了2的98次方倍,几乎可以说是用之不竭的。所以随着IPv4不足,支持IPv6的网络势必会增长。
  数据统计,世界上一些网络发达的国家已经开始逐渐用IPv6代替IPv4,这方面走在最前面的是比利时,其IPv6的流量比例已经占到27%,高于德国(11%)和美国(9.5%)。另外一些欧洲国家,如瑞士、卢森堡、罗马尼亚、捷克等国家也都表现良好,占比都在5%到9%之间。
  根据谷歌的统计,全球已经有5%的网络使用IPv6,相比去年取得了快速增长。很多高等学校都在普及IPv6,IPv6具有更大的地址空间、使用更小的路由表,并且更加安全,允许扩充。
  当然IPv6也并非十全十美的方案,与IPv4一样,IPv6一样会造成大量的IP地址浪费,而且在抵御DDoS攻击方面也存在缺陷。不过IPv6中有足够的地址为地球上每一平方英寸的地方分配一个独一无二的IP地址,这个优势无可匹敌,所以替代IPv4也是大势所趋。
大家感兴趣的内容
12345678910
最近更新的内容IPV6编程 - sxzxcm - 博客园
随笔 - 32, 文章 - 0, 评论 - 13, 引用 - 0
IPv6套接字编程1.概述由于互联网用户的日益增加,网络需求日益扩大,IPv4地址也日益紧张。人们为了解决地址日趋耗尽的问题,采用了CIDR、NAT等技术来延缓地址耗尽的速度,但这并不能从根本上解决IPv4目前存在的问题,IPv4地址耗尽只是一个时间问题。随着互联网的发展,Internet骨干路由器的路由表也日益扩大,这使得路由器必须维护大量路由表。由于IPv6可以解决传统的IP技术的瓶颈问题,因此,它会推动整个信息产业的发展。目前,第三代移动技术的基本协议就采用IPv6,这意味着下一代互联网具有移动性,将来手机或其他个人移动终端都将具有全球唯一的IPv6地址,因而IPv6技术将会变得越来越重要。1.1套接字与通信1.1.1套接字的概念套接字Socket,是指从应用程序中接受计算机网络通信服务时的应用程序接口,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。套接字是个抽象编程概念,它把用户代码与TCP/IP协议堆栈的底层实现隔离开了,TCP套接字可以使用户快速地开发出自定义协议的客户/服务器应用程序。套接字是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。可以将套接字看作不同主机间的进程进行双向通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中,通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。套接字通常和同一个域中的套接字交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序)。各种进程使用这个相同的域互相之间用Internet协议簇来进行通信。1.1.2套接字应用程序编程接口套接字应用程序编程接口是网络应用程序通过网络协议栈进行通信时所使用的接口,即应用程序与协议栈软件之间的接口,简称套接字编程接口(Socket API)。它定义了应用程序与协议栈软件进行交互时可以使用的一组操作,决定了应用程序使用协议栈的方式、应用程序所能实现的功能、以及开发具有这些功能的程序的难度。图1-1为应用进程通过套接字接入到网络的示意图。套接口是对网络中不同主机上应用进程之间进行双向通信的端点的抽象,一个套接口就是网络上进程通信的一端,提供了应用层进程利用网络协议栈交换数据的机制。要想实现套接字编程接口,可以采用两种实现方式:&&& 一种是在操作系统的内核中增加相应的软件来实现;&&& 一种是通过开发操作系统之外的函数库来实现。在这里我们采用的是第一种实现方式。1.1.3套接字的分类套接字具有三种类型:(1)数据报套接字(Datagram& SOCKET)数据报套接字提供无连接的不保证可靠的独立的数据报传输服务。在Internet通信域中,数据报套接字使用UDP数据报协议形成的进程间通路,具有UDP协议为上层所提供的服务的所有特点。图1-2揭示了基于UDP协议的数据报套接字的工作模型。(2)流式套接字(Stream SOCKET)&&&& 流式套接字提供双向的、有序的、无重复的、无记录边界的可靠的数据流传输服务。在Internet通信域中,流式套接字使用TCP协议形成的进程间通路,具有TCP协议为上层所提供的服务的所有特点,在使用流式套接字传输数据之前,必须在数据的发送端和接收端之间建立连接。 图1-3揭示了基于TCP协议的流式套接字的工作模型(3)原始式套接字(RAW SOCKET)原始式套接字允许对较低层次的协议,如IP、ICMP直接访问,用于检验新的协议的实现。每一个正被使用的套接字都有它确定的类型,只有相同类型的套接字才能相互通信。1.1.4套接字的应用场合(1)不管是采用对等模式或者客户机/服务器模式,通信双方的应用程序都需要开发。(2)双方所交换数据的结构和交换数据的顺序有特定的要求,不符合现在成熟的应用层协议,甚至需要自己去开发应用层协议,自己设计最适合的数据结构和信息交换规程。1.1.5套接字的一般通信过程网络通信一般为Client/Server模式Server:运行一个特定的程序,它申请一个Socket,该Socket在某一个Port监听客户机的连接。Client:申请一个Socket,将该Socket与服务器端的Port相联,服务器在接受该Client的连接后,新生成一个Port,在该新Port上与Client通信;原Port继续监听,准备接受新的Client的连接。图1-5 server通过另一个端口与client建立连接套接字是网络上与另一个应用程序建立连接并通信的一个句柄。1.2 IPv61.2.1 IPv6协议IPv6是因特网协议第六版(Internet Protocol Version Six)的缩写。目前,在Internet中广泛使用的IP协议是被人们称为IP第四版的IPv4协议。IPv4协议只使用了32位的IP地址,在迅速发展的Internet中,发生了地址的绝度数严重不足的问题。为了解决这个问题,人们对IP的第六版本进行了标准化,并且目前已经有一些操作系统对它进行支持。在IPv6协议中,IP地址的长度变为128位,在Internet中能够连接巨大数目的主机。IPv6协议对IPv4的改进表现在:(1)扩展地址空间。IP地址长度由32位增加到128位。(2)简化的首部格式,优化路由选择。IPv4首部的某些字段被取消或改为选项,以减少报文分组处理过程中常用情况的处理开销,并使得IPv6首部的带宽开销尽可能低。(3)支持扩展首部和选项。IPv6的选项放在单独的扩展首部中,位于报文分组中IPv6基本首部和传送层首部之间。因为大多数IPv6选项首部不会被报文分组投递路径上的任何路由器检查和处理,直至其到达最终目的地,这种组织方式有利于改进路由器在处理包含选项的报文分组时的性能。IPv6的另一改进,是其选项与IPv4不同,可具有任意长度,不限于40字节。(4)支持认证和加密机制。IPv6定义了一种扩展,可支持权限验证和数据完整性并支持保密性要求。(5)支持自动配置。IPv6支持多种形式的自动配置,从孤立网络结点地址的“即插即用”自动配置,到DHCP提供的全功能的设施。(6)服务质量能力。IPv6增加了一种新的能力,如果某些报文分组属于特定的工作流,发送者要求对其给予特殊处理,则可对这些报文分组加标号,例如非缺省服务质量通信业务或“实时”服务。1.2.2 IPv6数据报图1-6 为IPv6数据报报头0&&&&&&& 4&&&&&&&&&&&&&&& 12&&&&& 16&&&&&&&&&&&&&&& 24&&&&&&&&&&&&&& 31版本号&通信分类&流标识符&有效负载长度&下一首部&跳数限制&源地址(128位)&目的地址(128位)&有效负载(0-多个扩展首部+高层数据)&图1 IPv6数据报报头Ipv6协议的结构体定义如下:Struct ip6_hdr{& Union{Struct ip6_hdrctl{&& u_int32_t ip6_unl_/*4位的版本,8位的传输与分类,20位的流标识符*/u_int16_t ip6_unl_/*报头长度*/u_int8_t ip6_unl_/*下一个报头*/u_int8_t ip6_unl_/*跨度限制*/}ip6_u_int8_t ip6_un2_/*4位的版本号,跨度为4位的传输分类*/}ip6_struct in6_addr ip6_/*发送端地址*/struct in6_addr ip6_/*接收端地址*/};& #define ip6_vfc&&&&&&&&&&&&& ip6_ctlun.ip6_un2_vfc& #define ip6_flow&&&&&&&&&&&& ip6_ctlun.ip6_unl.ip6_unl_flow#define ip6_plen&&&&&&&&&&&& ip6_ctlun.ip6_unl.ip6_unl_plen#define ip6_nxt&&&&&&&&&&&&& ip6_ctlun.ip6_unl.ip6_unl_nxt#define ip6_hlim&&&&&&&&&&&& ip6_ctlun.ip6_unl.ip6_unl_hlim#define ip6_hops&&&&&&&&&&&& ip6_ctlun.ip6_unl.ip6_unl_hops1.3&& IPv6与IPv4的兼容性问题由于IPv6与IPv4在地址长度,数据报格式等方面存在许多不同点,因此在IPv6套接字编程的时候,如何使程序既能适应Ipv6的特点,又能消除不同地址间的差异,使程序既能处理IPv4的地址,又能处理IPv6地址,实现IPv6与IPv4的兼容,对程序编程者来说显得非常重要。IPv6套接字编程将综合考虑各种情况,解决IPv6与IPv4、IPv6与Ipv6节点间的通信问题。2.从IPv4网络向IPv6网络过渡目前,Internet中的绝大部分节点用的都是IPv4地址。为了解决IPv4地址的缺陷,Internet将逐步向IPv6过渡,在一段时间后,使Internet中所有的节点都具备处理IPv6地址的能力。为了达到这个目标,因特网工程任务组(IETF)已经设计出两种解决方案。通过这两种方案,可以使IPv6无缝地移植到IPv4中。这两种方法就是:双栈协议和隧道技术。双栈协议&&&& 双协议栈(dual stack)是指在完全过渡到 IPv6 之前,使一部分主机(或路由器)装有两个协议栈,一个 IPv4 和一个 IPv6。双栈网络的建设有两种模式:&&& (1)完全双栈网络,即所有网络设备、用户终端都支持IPv4、IPv6双协议栈,用户通信既可使用IPv4协议栈也可使用IPv6协议栈。&&& (2)有限双栈网络,网络中部分网络设备、用户终端采用双协议栈,这些用户可使用IPv4或IPv6与其它用户互联互通,但新增的网络设备和用户终端则仅使用IPv6协议栈,应用基于IPv6协议栈。双协议栈的具体工作方式如下:(1)若应用程序使用的目的地址为IPv4地址,则使用IPv4协议;(2)若应用程序使用的目的地址为IPv4兼容的IPv6地址,则同样使用IPv4协议,区别仅在于此时的IPv6封装在IPv4中;(3)若应用程序使用的目的地址是一个非IPv4兼容的IPv6地址,则使用IPv6协议,而且很可能要采用隧道等机制来进行路由传送;(4)若应用程序使用域名作为目标地址,则先从DNS服务器得到相应的IPv4/IPv6地址,然后根据地址情况进行相应的处理。2.2隧道技术&&& 所谓隧道,就是在一方将IPv6的包封装在IPv4包里,然后在目的地对其解析,得到IPv6包。通过隧道,IPv6分组被作为无结构无意义的数据,封装在IPv4数据报中,被IPv4网络传输。由于IPv4网络把IPv6数据当作无结构无意义数据传输,因此不提供帧自标示能力,所以只有在IPv4连接双方都同意时才能交换IPv6分组,否则收方会将IPv6分组当成IPv4分组而造成混乱。&在IPv6协议中,为了存储通信所需要的IP地址和端口号,定义了一个sockaddr_in6的结构体。sockaddr_in6的结构如下:struct sockaddr_in6{u_int8_t&&&&&&&&&&&&& sin6_u_int8_&&&&&&&&&&&&&& sin6_u_int16_t&&&&&&&&&&&& sin6_u_int32_t&&&&&&&&&&&& sin6_struct in6_addr&&&&&& sin6_u_int32_t&&&&&&&&&&&& sin6_scope_};数据类型u_int8_t为8位无符号整数,typedef unsigned char u_int8_t。u_int16_t 与u_int32_t亦类似。在sin6_len域中,存储有sockaddr_in6结构体的长度。在 sin6_family域中,存储有表示IPv6地址系列的AF_INET6.在sin6_port域中,存储有一个传输层所使用的端口号。在sin6_flowinfo域中,存储有一个在QoS中所使用的流标识符。在sin6_addr域中,存储有IPv6协议的地址。在sin6_scope_id域中,存储有表示范围的ID.IPv6协议的地址是由下面的int6_addr结构体加以定义的:struct int6_addr{u_int8_t s6_addr[16];};in6_addr与IPv6协议的地址相同为16Byte,但为了在操作系统内部处理方便起见,实际上是由联合体来定义的。在IPv4协议中,相对于sockaddr_in6结构体的为sockaddr_in结构体,其中缺少域sin6_flowinfo与sin6_scope_id。3.2 addrinfo&& addrinfo结构体是为了消除IPv6协议与IPv4协议之间的差异,编制统一的程序而追加的。在各台主机中,考虑能够赋予多个IPv4地址或IPv6地址,将addrinfo结构体设计为具有下面的列表结构:& Struct addrinfo{int&&&& ai_int&&&& ai_int&&&& ai_int&&&& ai_size_t& ai_char&&& *ai_struct sockaddr& *ai_struct addrinfo& *ai_& };在ai_flags域中,能够设定3位的标志位。它们分别是AI_PASSIVE、AI_CANONNAME、AI_NUMERICHOST。AI_PASSIVE在IPv4协议中指定INADDR_ANY的时候,不需要指定具体的主机,而是利用任意的主机。AI_CANONNAME是在最初的列表结构中存储正式名称的时候所设定的值。AI_NUMERICHOST不使用DNS进行检索,只使用IP地址,它在不想使用DNS查询处理、需要等待一定时间的时候等情况下才使用。ai_family域表示了地址系列。在地址系列中,具有表示IPv4协议的AF_INET、IPv6协议的AF_INET6等。ai_socktype域表示了套接字的类型。在一个套接字的类型域中,具有下面的三种类型:表示流型的SOCK_STREAM,表示数据报型的SOCK_DGRAM,表示raw IP的SOCK_RAW。ai_protocol域表示了传输层所使用的协议。在使用TCP协议时,它为IPPROTO_TCP;在使用UDP协议时,它为IPPROTO_UDP;在不使用传输层时,在该域中存储0.ai_addrlen域表示ai_addr的长度。ai_canonname域表示ai_addr的别名。ai_addr域表示了访问sockaddr_in或sockaddr_in6的指针。ai_next域表示列表的下一个地址。在列表结束时,在该域中存储NULL。4.IPv6套接字编程中用到的函数4.1 socket()函数在使用套接字的时候,利用socket系统调用来打开一个套接字。socket系统调用的语法如下所示:#include &sys/types.h&#include &sys/socket.h&int socket(int domain,int type,int protocol);在domain域中,指定地址系列(协议系列)。地址系列表示所使用的地址体系。在TCP/IP协议中,将IP地址和端口号所形成的地址体系指定为AF_INET或AF_INET6,将表示TCP/IP协议的地址体系指定为PF_INET。在type变量中,指定所使用的协议的类型,其中可以指定下面的值:#define sock_STREAM&&&&&&&& /*流式套接字*/#define sock_DGRAM&&&&&&&& /*数据报套接字*/#define sock_RAW&&&&&&&&&&& /*原始式套接字*/#define sock_RDM&&&&&&&&&&& /*可靠传输报文*/#define sock_SEQPACKET&&&& /*序列包流*/在使用TCP协议时,指定为SOCK_STREAM;在使用UDP协议时,指定为SOCK_DGRAM;在使用原始IP协议时,指定为SOCK_RAW。在protocol域中,指定所使用的协议类型。在使用TCP协议或UDP协议时,由于指定type就可以确定方法,所以在protocol域中,缺省值为0。如果成功地调用了socket系统调用,则打开一个套接字,并且返回一个可以利用该套接字的描述符。在发生错误时,则返回值为-1。4.2 bind()函数在利用自己的主机指定所使用的IP地址和端口号时,一般都使用bind系统调用。关于bind系统调用语法,如下所示:#include &sys/types.h&#include &sys/socket.h&int bind(int s,struct sockaddr *my_addr,socklen_t addrlen);在变量s中,指定的是利用socket系统调用所打开的套接字的描述符。在my_addr指针中,指定自己的IP地址和端口号。在addrlen域中,指定结构体my_addr的大小。在利用bind系统调用将一个IP地址设置为INADDR_ANY的时候,该主机或路由器的所有IP地址都能够接收到一个包。在主机中,除了NIC的IP地址之外,都带有一个循环测试(loopback)的IP地址(127.0.0.1)。并且,在使用路由器等时,由于准备了多个接口,所以带有多个IP地址。这时,如果使用bind系统调用来指定一个IP地址,那么处理IP数据报的接收端地址和指定的IP地址之外,不能够接收到通信。但是,在指定为INADDR_ANY时,无论接收端的IP地址是什么,都能够接收到包。在服务器中,无论是TCP协议还是UDP协议,都必须使用bind系统调用来指定自己的端口号。在客户机中,可以有操作系统来指定一个端口号。如果使用bind系统调用来指定的端口号时,能够自动地分配一个端口号。另外,在TCP协议的客户机中,可以省略执行bind系统调用。4.3 close()函数在结束对套接字的使用的时候,使用close系统调用。关于close系统调用的语法,如下面的语句所示:#include &unistd.h&int close(int s);在变量s中,存储着利用socket系统调用所打开的套接字的描述符,或存储着accept系统调用的返回值。4.4 sendto()函数&&& 套接字函数可以分为两种:一种为无连接型的函数,另一种为面向连接型的函数。&&& #include &sys/types.h&&&& #include &sys/socket.h&&&& int sendto(int s,const void *msg,size_t len,int flags,const struct sockaddr *to,socklen_t tolen);在raw IP协议中,必须使用无连接型的函数。在UDP协议中,通常都是使用无连接型的函数,但是,也可以使用面向连接型的函数。在TCP协议中,必须使用面向连接型的函数。在UDP协议中,如果没有使用connect系统调用,则可以使用一个无连接型的函数。如果使用connect系统调用,也可以使用一个面向连接型的函数。对于报文的发送与接收,可以利用sendto系统调用或recvfrom系统调用。在发送报文的时候,使用sendto系统调用;而在接收报文的时候,则使用recvfrom系统调用。无论是哪一种系统调用,都必须在实际参数中指定访问sockaddr结构体的指针。在变量s中,指定的是一个利用socket系统调用所打开的端口号描述符。在msg结构体中,存储着所发送报文的存储器的初始地址,在len变量中,指定的是所发送报文的字节数;在to结构体中,指定的是接收端的IP地址和接收端的端口号;在tolen变量中,指定结构体to的大小;在flags变量中,通常指定为0。sendto系统调用的返回值是已经发送报文的字节数。严格地来讲,该返回值并不是在计算机网络上所传输的字节数,而是从应用程序传递给套接字模块的字节数。在发生错误时,返回值为-1。4.5 recvfrom()函数#include &sys/types.h&#include &sys/socket.h&int recvfrom(int s,void *hbuf,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen);在变量s中,指定的是利用socket系统调用所打开的一个套接字描述符。在buf指针中,存储的是所接收到报文的缓冲区的起始地址;len变量中指定的是buf中所能够存储的最大字节数。在from结构体中,存储着所接收到的包的发送端IP地址和发送端端口号;在fromlen变量中,存储这结构体from的大小;在flags变量中,通常指定为0。recvfrom系统调用的返回值是所接收到的报文的字节数。在发生错误时,返回值为-1。4.6 connect()函数&&& 在指定通信对方的IP地址的时候,通常采用connect系统调用。在TCP协议中,需要传输建立连接请求的包。在UDP协议中,并不使用sendto系统调用或recvfrom系统调用,而是通过send系统调用或recv系统调用进行通信。connect系统调用的语法格式如下:&&& #include &sys/types.h&#include &sys/socket.h&int connect(int s,const struct sockaddr *addr,socklen_t addrlen);在变量s中,指定的是利用socket系统调用所打开的一个套接字描述符。在addr结构体中,指定的是通信对方的IP地址和端口号。在addrlen变量中,指定的是addr结构体的大小。4.7 listen()函数当服务器接收到TCP协议连接的时候,执行一个listen系统调用。关于listen系统调用的语法格式如下:#include &sys/socket.h&int listen(int s,int backlog);在变量s中,存储着利用socket系统调用所打开的一个套接字描述符。在backlog变量中,指定的是队列的长度。如果listen系统调用正常,则返回值为0;否则发生错误时,返回值为-1。4.8 getaddrinfo()函数IPv4中使用gethostbyname()函数完成主机名到地址解析,但是该API不允许调用者指定所需地址类型的任何信息,返回的结构只包含了用于存储IPv4地址的空间。为了解决该问题,IPv6中引入了getaddrinfo()的新API,它是协议无关的,既可用于IPv4也可用于IPv6。getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,调用该函数会获得一个addrinfo结构的列表,调用的返回值是addrinfo的结构(列表)指针。#include &sys/socket.h&#include &netdb.h&int getaddrinfo(const char* nodename,const char* servname,const struct addrinfo* hints,struct addrinfo** res);nodename域指定了一个域名或IP地址。在这个域中,既能够指定IPv6协议的地址,又能够指定IPv4协议的地址。servname域能够指定表示端口号的服务器名或表示端口号的数字。在指定一个域名或服务器名的时候,与使用C语言处理字符串的规则是相同的,在字符串的最后要追加。在hints域中,指定想要获得的信息。例如,在只想获得与IPv6协议有关的信息时,在addrinfo结构体的ai_family中设定AF_INET6之后,再指定hints。在不特别指定时,将hints域设置为NULL。在res域中,使用一个addrinfo结构体来保存;列表结构的开始地址。在IPv6协议中,在一个端口能够指定多个IP地址。并且在过渡期中,也有将IPv6地址和IPv4地址这两种地址都赋予一个NIC(网络适配器、网卡)的情况存在。调用一次getaddrinfo函数,即可检索到所以的IP地址,并使用一个addrinfo结构体存储到该列表结构中。4.9 getnameinfo()函数&&& getnameinfo()是getaddrinfo()的互补函数。它把一个套接字地址转换为对应的主机名和服务。它是一个“协议无关”的函数,既能处理IPv4地址,又能处理IPv6地址。它集合了gethostbyaddrin()函数和getservbyport()函数的功能,但getnameinfo()消除了地址族依靠的特性。#include &sys/socket.h&#include &netdb.h&int getnameinfo(const struct sockaddr *sa, socklen_t salen,&&&&&&&&&&&&&&&&&&&&&& char *host, size_t hostlen,&&&&&&&&&&&&&&&&&&&&&& char *serv, size_t servlen, int flags);sa域是一个指向sockaddr结构体的指针,其中指定了IP地址和端口号。host域是存放主机名的字符型指针,而serv域是存放服务的指针,即端口号。flag域用于控制getnameinfo()的操作,它允许的值如下面所列:NI_DGRAM当知道处理的是数据报套接口的时候,调用者应该设置NI_DGRAM标志,因为在套接口地址结构中给出的仅仅是IP地址和端口号,getnameinfo无法就此确定所用协议是TCP还是UDP。比如端口514,在TCP端口上提供rsh服务,而在UDP端口上则提供syslog服务。NI_NOFQDN该标志导致返回的主机名称被截去第一个点号之后的内容。比如假设套接口结构中的IP地址为91.168.42.2,那么不设置该标志返回的主机名为,那么如果设置了该标志后返回的主机名则为sina。NI_NUMERICHOST,NI_NUMERICSERV,NI_NUMERICSCOPENI_NUMERICHOST标志通知getnameinfo不要调用DNS,而是以数值表达格式作为字符串返回IP地址;类似的,NI_NUMERICSERV标志指定以十进制数格式作为字符串返回端口号,以代替查找服务名;NI_NUMERICSCOPE则指定以数值格式作为字符串返回范围标识,以代替其名字。NI_NAMEREQD该标志通知getnameinfo函数如果无法适用DNS反向解析出主机名,则直接返回一个错误。需要把客户的IP地址映射成主机名的那些服务器可以使用该特性。4.10 inet_pton()函数和inet_ntop()函数inet_pton函数是一个将域名或ASCII码表示的IP地址变换为使用字节来表示的IP地址的函数。inet_ntop函数则是inet_pton函数的逆,即把使用字节来表示的IP地址转为使用字符串所表示的IP地址。#include &sys/types.h&#include &sys/socket.h&#include &netinet/in.h&#include &arpa/inet.h&int inet_pton(int af,const char *src,void *dst);const char *inet_ntop(int af,const void *src,char *dst,size_t size);在af域中,指定地址系列;在src、dst域中,分别指定变换前所存储的地址信息以及返回后所存储的地址信息。在inet_ntop的size域中,指定了从dst开始的缓冲区的大小。如果不指定充分大的缓冲区,则不能够进行变换处理。4.11 memset()函数&&& void *memset(void *s,int c,size_t n)memset函数用来对一段内存空间全部设置为某个字符,常用于内存空间初始化。将已开辟内存空间s的首n个字节的值设为值c。4.12 memcpy()函数extern void *memcpy(void *dest, void *src, unsigned int count);memcpy函数把src所指内存区域复制count个字节到dest所指内存区域,但src和dest所指内存区域不能重叠,函数返回指向dest的指针。memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,而strcpy就只能拷贝字符串了,它遇到'\0'就结束拷贝。5.程序的地址族无关性5.1 地址族无关的概念在套接字编程中,我们经常说到程序必须实现地址族无关(address-family independent)。什么是地址族无关呢?所谓的地址族无关,就是要求程序在处理IP地址时,能消除不同IP地址间的差异性,可对不同的IP地址进行统一的无差别的处理。不需修改程序,即可对不同的IP地址进行预定的处理,实现相应功能。5.2 为什么程序需要地址族无关&& 程序具备地址族无关性可以使程序消除一系列不足,使程序更具灵活性:(1)为了支持IPv4/v6双栈环境,网络程序必须能够同时正确处理IPv4与IPv6。如果在程序中规定了地址族为AF_INET或AF_INET6,那么程序将无法在IPv4/v6双栈环境中正确运行。(2)当一个新的协议投入使用后,我们总是希望以前的网络程序能够适应新协议,而不需为了适应新协议而对程序进行重写。这包括在IP层,虽然现在还没有开发IPv7的计划,但谁也不能肯定未来会不会开发。在传输层亦如此。(3)目前,已经有足够的工具支持网络程序的地址族无关,比如sockaddr_storage,getaddrinfo和getnameinfo。(4)在一些操作系统中可能不支持地址族。如果在编程中引入了地址族,可能会导致程序不能正确执行。而程序的地址族无关可以解决此类问题。(5)程序的地址族无关可以使程序更简洁,提高程序的移植性。(6)有些应用程序接口(API)不支持IPv6,比如gethostbyname()。5.3 以AF_INET6替代AF_INET,sockaddr_in6替代sockaddr_in的不足在重写IPv4依靠(IPv4 dependent)程序的时候,能不能只是简单地把AF_INET代替为AF_INET6,sockaddr_in替代为sockaddr_in6,而使程序地址族无关呢?这样做有几个缺点:首先,用gethostbyname2(3),程序只能连接IPv6目的地址,而不能连接IPv4目的地址。在一个IPv4/v6双栈环境中,FQDN(Fully Qualified Domain Name,完全合格域名/全称域名,是指主机名加上全路径,全路径中列出了序列中所有域成员)可以被分解为多个IPv4地址和多个IPv6地址。客户端应该尽可能地连接分解出来的IP地址,而不只是连接IPv6地址。第二,IPv6支持范围IPv6地址(scoped IPv6 addresses),用gethostbyname2(3)并不能处理范围IPv6地址,因为gethostbyname2(3)不返回范围标识符(scope& identification)。第三,在程序中指定地址族为AF_INET6将使程序只能在支持IPv6的内核中运行,因为一个不支持IPv6的内核通常没有AF_INET6套接字的支持。如果想让一个单一双态程序(既能处理IPv4地址,又能处理IPv6地址)能正确运行在IPv4-only内核、IPv6内核和IPv4/v6双栈内核中,地址族无关是必须的。第四,这样的程序并不能适应未来的需要。如果一些新协议投入使用,这样的程序将不可避免重写。IPv4到IPv6的过渡的花费是巨大的,在此过渡过程中,把其他问题一起解决未尝不是一件好事。第五,用地址族无关方法进行编程,可以使程序获得更高的移植性和稳定性。5.4 套接字编程的地址族无关指南(1)使用sockaddrs用于地址表示为了处理IPv4和IPv6地址,建议使用sockaddrs,如sockaddr_in或sockaddr_in6。用sockaddrs,可以使数据包含地址族的标识,这样的话我们就可以在传递地址数据时知道其地址族。当需要一个预留空间给一个sockaddr时,可以使用结构体sockaddr_storage。结构体sockaddr_storage有足够大的空间来存储任何类型的sockaddr。使用sockaddr的另一个重要原因是一个IPv6地址并不能唯一地确定一个端点,还必须加上一个一个范围标识符,指定出口端(outgoing interface)。(2)把文本表示转换为sockaddrs。利用getaddrinfo(3)可以实现。(3)把二进制地址表示转换为文本。可以利用getnameinfo(3)实现。6.IPv6套接字编程6.1& 编写能处理IPv6地址的程序为了使程序能够处理IPv6地址,我们知道可以用基于socket的应用程序接口,通过使用getaddrinfo和getnameinfo来使程序具备地址族无关的能力。getaddrinfo()应用举例:const struct sockaddr * foo(hostname,servname)&&&& const char *&&&& const char *{&&&& struct addrinfo hints,*&&&& static struct sockaddr_&&&&&&&& memset(&hints,0,sizeof(hints));&&&& hints.ai_socktype=SOCK_STREAM;&&&& error=getaddrinfo(hostname,servname,&hints,&res);&&&& if(error){&&&&&&& fprintf(stderr,”%s/%s:%s\n”,hostname,servname,gai_strerror(error));&&&&&&& exit(1);&&& }&&& if(res-&ai_addrlen sizeof(ss)){&&&&&&& fprintf(stderr,”sockaddr too large\n”);&&&&&&& exit(1);&&& }&&& memcpy(&ss,res-&aiaddr,res-ai_addrlen);&&& freeaddrinfo(res);&&& return(const struct sockaddr *)&}getaddrinfo(3)非常灵活,具有许多状态操作。比如,如果你想避免DNS lookup,你可以在hints.ai_flags域中指定为AI_NUMERICHOST。通过AI_NUMERICHOST,getaddrinfo(3)将只接收数字表示的地址。getaddrinfo(3)用范围识别(scope identification)处理IPv6字符串地址,所以程序不需要对范围识别做任何的特殊处理。getnameinfo(3)也非常灵活,既支持数字的地址,也支持FQDN(Fully Qualified Domain Name:完全合格域名/全称域名,是指主机名加上全路径,全路径中列出了序列中所有域成员)表示的地址。getnameinfo(3)同时也可以把端口号转换成字符串。所以getnameinfo(3)能同时支持IPv4和IPv6,并不需要区分是支持IPv4还是支持IPv6。最后一个参数可以控制getnameinfo(3)的行为。struct sockaddr *char hbuf[NI_MAXHOST];sbuf[NI_MAXSERV] ;error=getnameinfo(sa,salen,hbuf,sizeof(hbuf),&& NI_NUMERICHOST|NI_NUMERICSERV);if(error){fprintf(stderr,”error:%s\n”,gai_strerror(error));exit(1);}fprintf(“addr:%s port:%s\n”,hbuf,sbuf);error=getnameinfo(sa,salen,hbuf,sizeof(hbuf),0);if(error){fprintf(stderr,”error:%s\n”,gai_strerror(error));exit(1);}fprintf(“addr:%s port:%s\n”,hbuf,sbuf);error=getnameinfo(sa,salen,hbuf,sizeof(hbuf),NULL,0,NI_NAMEREQD);if(error){fprintf(stderr,”error:%s\n”,gai_strerror(error));exit(1);}printf(“FQDN:%s\n”,hbuf);getnameinfo(3)需要生成IPv6地址字符串的范围标识,但也没必要担心在sin6_scope_id域中的范围标识。6.2移植可用的程序来支持IPv6为了找到需要重写的部分,我们需要找出IPv4依赖的功能调用和IPv4依赖的数据类型:%grep gethostby *.c *.h%grep inet_aton *.c *.h%grep sockaddr_in *.c *.h%grep in_addr *.c *.h然而,如果程序编写不正确并且在int或u_int32_t中传递32位的二进制表示的IPv4地址的话,对in_addr将毫无用处,还需识别在哪个变量中存储了IPv4地址。如果套接字编程借口(socket API)是由单个*.c文件生成,那么将容易移植。否则,我们必须弄清IPv4依靠的数据是怎样传送的,然后把它们重写成协议族无关的程序。有时候,IPv4依靠的数据类型用在结构体定义和功能原型中。在这种情况下,我们需要辨别出地址族无关的代码。下面的例子是IPv4依赖的部分程序代码:struct foo{struct sockaddr_}struct foo *setaddr(in)&&&&& struct in_{&&&&& struct foo *&&&&& foo=malloc(sizeof(*foo));&&&&& if(!foo)&&&&&&&&& return NULL;&&&&& memset(foo,0,sizeof(*foo));&&&&&&&&& foo-&dst.sin_family=AF_INET;&&&&&&&&& foo-&dst.sin_addr=&&&&&&&&&}改变结构体的定义是比较简单的,要么把结构体改为struct sockaddr_storage,要么定义一个struct addrinfo*。而改为功能原型则要难得多。有时候,传递struct sockaddr *会容易些,但如果你要处理多个地址的话,用struct addrinfo *会显得更明智些。下面是重写后的程序,实现了地址族无关,但不支持多地址:struct foo{&&&& struct sockaddr_};struct foo *setaddr(sa,salen)&&&&&& struct sockaddr *&&&&&& socklen_{&&&&&& struct foo *&&&&&&&&&& if(salen&sizeof(foo-&dst))&&&&&&&&&&&&&&& return NULL;&&&&&&&&&& foo=malloc(sizeof(*foo));&&&&&&&&&& if(!foo)&&&&&&&&&&&&& return NULL;&&&&&&&&&& memset(foo,0,sizeof(*foo));&&&&&&&&&& memcpy(&foo-&dst,sa,salen);&&&&&&&&&&}如果由于一些限制不能使用select(2)和poll(2),可以运行两个应用程序的实例,一个用于AF_INET socket,另一个用于AF_INET6,这样就可以同时处理IPv4节点和IPv6节点。结论及尚存在的问题IPv6的主要优势体现在以下几方面:扩大地址空间、提高网络的整体吞吐量、改善服务质量(QoS)、安全性有更好的保证、支持即插即用和移动性、更好实现多播功能。显然,IPv6的优势能够直接或间接地解决IPv4存在的诸多问题。其中最突出的是IPv6大大地扩大了地址空间,恢复了原来因地址受限而失去的端到端连接功能,为互联网的普及与深化发展提供了基本条件。当然,IPv6并非十全十美、一劳永逸,不可能解决所有问题。IPv6只能在发展中不断完善,也不可能在一夜之间发生,过渡需要时间和成本,但从长远看,IPv6有利于互联网的持续和长久发展。由于IPv6相关技术目前还不是很成熟,其应用范围还不是很广,很多方面还只是停留在研究与实验阶段,因此本毕业论文的讨论范围也涉及不深,只作浅层次的探索讨论;在程序移植性方面也不是做的很好,本设计的代码是在Linux平台下调试运行的,因此在跨平台方面还有待提高。在这次毕业设计的过程中,我查阅了大量相关的书籍与相关知识,通过自学与老师的指导,我对毕业设计的要求与内容有了深刻的了解,并通过自己的理解与分析思考,圆满完成了毕业论文。在完成毕业设计的过程中,我对“一份耕耘,一份收获”有了深刻的认识,只要你付出了,你就一定会有收获。在毕业设计期间,我认真查阅资料,虚心请教老师与同学,并仔细弄清相关理论知识,理清思路,详细构思规划,很快就有了一个大致的框架,在后期通过修改与完善,我的论文完成了。在此过程中,我付出了努力,而我也取得了收获。我学到了很多以前课堂上没学到的知识,在IPv6相关知识方面有了更深的理解,并在此过程中,我的查阅资料能力、整体构思规划能力、解决问题的能力也得到了提高,我从中受益甚大。致& 谢大学生活即将画上记号,而于我的人生却只是一个逗号,我将面对又一次征程的开始。四年的求学生涯在师长、亲友的大力支持下,走得辛苦却也收获满囊,在论文即将付梓之际,思绪万千,心情久久不能平静。伟人、名人为我所崇拜,可是我更急切地要把我的敬意和赞美献给我的大学老师们,是你们的无私教导让我从稚嫩走向成熟,而我也从中学到各种知识与智慧,让我可以更容易地面对社会生活。在这里,我要特别感谢我的指导老师罗海天老师,他给了我很大的帮助,帮我解决了毕业设计中遇到的很多问题。从论文题目的选定到论文写作的指导,经由他悉心的点拨,再经思考后的领悟,常常让我有“山重水复疑无路,柳暗花明又一村”的感觉。授人以鱼不如授人以渔,置身其间,耳濡目染,潜移默化,使我不仅接受了全新的思想观念,树立了宏伟的学术目标,领会了基本的思考方式,从罗老师的身上,我受益良多。感谢我的爸爸妈妈,焉得谖草,言树之背,养育之恩,无以回报,你们永远健康快乐是我最大的心愿。在论文即将完成之际,我的心情无法平静,从开始进入课题到论文的顺利完成,有多少可敬的师长、同学、朋友给了我无言的帮助,在这里请接受我诚挚谢意!同时也感谢学院为我提供良好的做毕业设计的环境。最后再一次感谢所有在毕业设计中曾经帮助过我的良师益友和同学,以及在设计中被我引用或参考的论著的作者。本毕业设计是我学习生涯的最后一份答卷,也是我作为学生交给母校最后的一份答卷,尽管倾注了我数月来的心血和汗水,却由于自己的基础知识不够扎实,能力确实有限,多多少少存在着这样那样的缺陷。然而,毕竟已经尽力,已无憾矣!附录程序1 client-gethostby.c:TCP客户端实例——通过host/port与服务端通信,并从服务端接收信息。该程序不支持IPv6。#include &sys/types.h&#include &sys/socket.h&#include &netinet/in.h&#include &netdb.h&#include &stdio.h&#include &errno.h&#include &unistd.h&#include &string.h&#include &stdlib.h&#include &arpa/inet.h&int main_P((int,char **));int main(argc,argv)&&&&&&&&&&&&&& char **{&&&&&&& struct hostent *&&&&&&& struct servent *&&&&&&&&&&&&&& u_int16_t&&&&&&&& char *&&&&&&& struct sockaddr_&&&&&&&ssize_&&&&&&&&&&&&&& char hbuf[INET_ADDRSTRLEN];&&&&&&& char buf[1024];/*检查参数个数*/&&&&&& if(argc!=3){&&&&&&&& fprintf(stderr,”usage:test host port\n”);&&&&&&&& exit(1);&&&&&& }&&&&&& /*把主机名解释为IP*/&&&&&& hp=gethostbyname(argv[1]);&&&&&& if(!hp){&&&&&&&& fprintf(stderr,”%s:%s\n”,argv[1],hstrerror(h_errno));&&&&&&&& exit(1);&&&&& }&&&&& if(hp-&h_length!=sizeof(dst.sin_addr)){&&&&&&&& fprintf(stderr,”%s:unexpected address length\n”,argv[1]);&&&&&&&& exit(1);&&&&& }&&&&& /*解析端口号*/&&&&& sp=getservbyname(argv[2],”tcp”);&&&&& if(sp){&&&&&&&& port=sp-s_port& 0&&&&& }else{&&&&&&&&&& ep=NULL;errno=0;&&&&&&&&&& lport=strtoul(argv[2],&ep,10);&&&&&&&&&& if(!*argv[2] || errno || !ep || *ep){&&&&&&&&&&&& fprintf(stderr,”%s:no such service\n”,agrv[2]);&&&&&&&&&&&& exit(1);&&&&&&&&&& }&&&&&&&&&& if(lport & ~0xffff){&&&&&&&&&&&& fprintf(stderr,”%s:out of range\n”,argv[2]);&&&&&&&&&&&& exit(1);&&&&&&&&&& }&&&&&&&&&& port=htons(lport & 0xffff);/*将主机的无符号短整数型数转换为网络字节顺序,如12 34&#*/&&&&&& }&&&&&& endservent() ;&&&&&& /*只尝试第一个地址*/&&&&&& memset(&dst,0,sizeof(dst)) ;&&&&&& dst.sin_family=AF_INET ;&&&&&& /*Linux/Solaris系统不需要下面的一行*/&&&&&& dst.sin_len=sizeof(struct sockaddr_in) ;&&&&&& memcpy(&dst.sin_addr,hp-&h_addr,sizeof(dst.sin_addr)) ;&&&&&& dst.sin_port=&&&&&& dstlen=sizeof(struct sockaddr_in) ;&&&&&& s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);&&&&&& if(s&0){&&&&&&&&& perror(“socket”);&&&&&&&&& exit(1);&&&&&& }&&&&&& inet_ntop(AF_INET,hp-&h_addr,hbuf,sizeof(hbuf));&&&&&& fprintf(stderr,”trying %s port %u\n”,,hbuf,ntohs(port));&&&&&& if(connect(s,(struct sockaddr *)&dst,dstlen)&0){&&&&&&&&& perror(“connect”);&&&&&&&&& exit(1);&&&&&& }&&&&&& while((l=read(s,buf,sizeof(buf))&0)&&&&&&&&&&&& write(STDOUT_FILENO,buf,l);close(s);&&&&&&&&&&&& exit(0);&&&&&& }程序2 client-getaddrinfo.c:在程序6-1的基础上使程序实现地址族无关。#include &sys/types.h&#include &sys/socket.h&#include &netinet.h&#include &netdb.h&#include &stdio.h&#include &errno.h&#include &unistd.h&#include &string.h&int main_P((int,char **));int main(argc,argv)&&&&&&&&&&&&&& char **{&&&&&&& struct addrinfo hints,*res,*res0;&&&&&&& ssize_&&&&&&&&&&&&&& char hbuf[NI_MAXHOST],sbuf[NI_MAXSERV];&&&&&&& char buf[1024] ;&&&&&&&/*检查参数个数*/&&&&&& if(argc!=3){&&&&&&&& fprintf(stderr,”usage:test host port\n”);&&&&&&&& exit(1);&&&&&& }/*把地址/端口号转换为sockaddr,基于getaddrinfo(3)返回的结果,程序代码运行于数据驱动模式*/&&&&&& memset(&hints,0,sizeof(hints)) ;&&&&&& hints.ai_socktype=SOCK_STREAM;&&&&&& error=getaddinfo(argv[1],argv[2],&hints,&res0);&&&&&& if(error){&&&&&&&&& fprintf(stderr,”%s %s\n”,argv[1],argv[1],gai_strerror(error));&&&&&&&&& exit(1);/*尝试所有的sockaddr直到通信成功*/&&&&&& for(res=res0;res=res-&ai_next){&&&&&&&&&& error=getnameinfo(res-&ai_aiaddr,res-&ai_addrlen,hbuf,sizeof(hbuf),sbuf,sizeof(sbuf),NI_NUMERICHOST | NI_NUMERICSERV);&&&&&&&&&& if(error){&&&&&&&&&&&&& fprintf(stderr,”%s%s:%s\n”,arg[1],argv[1],gai_sterror(error));&&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&&&& fprintf(stderror,”trying %s port %s\n”,hbuf,sbuf);&&&&&&&&&& s=socket(res-&ai_family,res-&ai_socktype,res-&ai_protocol);&&&&&&&&&& if(s&0)&&&&&&&&&&&&&&&&&&&& if(connect(s,res-ai_addr,res-ai_addrlen)&0){&&&&&&&&&&&&&& close(s);&&&&&&&&&&&&&& s=-1;&&&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&&&& while((l=read(s,buf,sizeof(buf)))&0)&&&&&&&&&&&&&&& write(STDOUT_FILENO,buf,l);close(s);&&&&&&&&&&& exit(0);&&&&&&&&&&& }&&&&&&&&&&& fprintf(stderr,”test:no destination to connect to\n”);&&&&&&&&&&& exit(1);&&&&&&&&&&& }程序3 server-single.c 一个独立的TCP服务器侦听一个IPv4端口#include &sys/types.h&#include &sys/socket.h&#include &netinet/in.h&#include &netdb.h&#include &stdio.h&#include &errno.h&#include &unistd.h&#include &string.h&#include &stdlib.h&#include &arpa/inet.h&int main_P((int,char **));int main(argc,argv)&&&&&&&&&&&&&& char **{&&&&&&& struct servent *&&&&&&&&&&&&&& u_int16_t&&&&&&&& char *&&&&&&& struct sockaddr_&&&&&&&struct sockaddr_&&&&&&& socklen_&&&&&&&&&&&&&&&&&&&&& char hbuf[INET_ADDRSTRLEN];if(argc!=2){&&&&&&&&&& fprintf(stderr,”usage:test port\n”);&&&&&&&&&& exit(1);&&&&&& }&&&&&& sp=getservbyname(argv[1],”tcp”);&&&&&& if(sp)&&&&&&&&&& port=sp-&s_port & 0&&&&&& else{&&&&&&&&&& ep=NULL;errno=0;&&&&&&&&&& lport=strtoul(argv[1],&ep,10) ;&&&&&&&&&& if(!*argv[1] || errno || !ep || *ep){&&&&&&&&&&&&& frpintf(stderr,”%s: no such service\n”,argv[1]);&&&&&&&&&&&&& exit(1);&&&&&&&&&& }&&&&&&&&&& if(lport & ~0xffff){&&&&&&&&&&&&& fprintf(stderr,”%s: out of range\n”,argv[1]);&&&&&&&&&&&&& exit(1);&&&&&&&&&& }&&&&&&&&& port=htons(lport &0xffff);&&&&&& }&&&&&& endservent() ;&&&&&& memset(&serv,0,sizeof(serv)) ;&&&&&& serv.sin_family=AF_INET ;&&&&&& /*Linux/Solaris系统不需要下面的一行*/&&&&&& serv.sin_len=sizeof(struct sockaddr_in) ;&&&&&& serv.sin_port=&&&&&& servlen=sizeof(struct sockaddr_in);&&&&&& s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);&&&&&& if(s&0){&&&&&&&&& perror(“socket”);&&&&&&&&& exit(1);&&&&&& }&&&&&& if(bind(s,(struct sockaddr *)&serv,servlen)&0){&&&&&&&&& perror(“bind”);exit(1);&&&&&& }&&&&&& if(listen(s,5)&0{perror(“listenexit(1);&&&&&& }&&&&&& while(l){&&&&&&&&& fromlen=sizeof(from);&&&&&&&&& ls=accept(s,(struct sockaddr *)&from,&fromlen);&&&&&&&&& if(ls&0)&&&&&&&&&& if(from.sin_family!=AF_INET || fromlen!=sizeof(struct sockaddr_in)){exit(1);&&&&&& }&&&&&&&&& if(inet_ntop(AF_INET, &from.sin_addr,hbuf,sizeof(hbuf))= =NULL){exit(1);&&&&&& }&&&&&&&& write(ls,”hello”,6);&&&&&&&& write(ls,hbuf,strlen(hbuf));&&&&&&&& write(ls,”\n”,l);&&&&&&&& close(ls);&&&&&& }}程序4 server-getaddrinfo.c 在程序6-3的基础上使程序地址族无关#include &sys/types.h&#include &sys/socket.h&#include &netinet/in.h&#include &netdb.h&#include &stdio.h&#include &errno.h&#include &unistd.h&#include &string.h&#include &stdlib.h&#include &arpa/inet.h&#define MAXSOCK 20int main_P((int,char **));int main(argc,argv)&&&&&&&&&&&&&& char **{&&&&&&& struct addrinfo hints,*res,*res0;&&&&&&&&&&&&&& struct sockaddr_&&&&&&& socklen_&&&&&&&&&&&&&& int s[MAXSOCK];&&&&&&&&&&&&&&&&&&&&& fd_set rfd,rfd0;&&&&&&&&&&&&&&&&&&&&& char hbuf[NI_MAXHOST],sbuf[NI_MAXSERV];#ifdef IPV6_V6ONLY&&&&&&& const int on=1 ;#endif&if(argc!=2){&&&&&&&& fprintf(stderr,”usage:test port\n”);&&&&&&&& exit(1);&&&&&& }memset(&hints,0,sizeof(hints)) ;&&&&&& hints.ai_socktype=SOCK_STREAM;&&&&&& hints.ai_flags=AI_PASSIVE;&&&&&& error=getaddinfo(NULL,argv[1],&hints,&res0);&&&&&& if(error){&&&&&&&&& fprintf(stderr,”%s %s\n”,argv[1], gai_strerror(error));&&&&&&&&& exit(1);}smax=0;sockmax=-1;for(res=res0;res &&smax rMAXSOCK; res=res-&ai_next){&&&& s[smax]=socket(res-ai_family,res-ai_socktype,res-&ai_protocol);&& if(s[smax]&0&/*避免FD_SET溢出*/if(s[smax]=FD_SETSIZE){&& close(s[smax]);&& s[smax]=-1;&&}#ifdef IPV6_V6ONLY&&&&&& if(res-&ai_family= =AF_INET6 &&setsockopt(s[smax],IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on))&0){&& perror(“bind”);&& s[smax]=-1;&&}#endif&&&&&&&&&&&&&&&&&&& if(bind(s[smax],res-ai_addr,res-ai_addrlen) 0){&&&&&&&&&&&&&&&&& close(s[smax]);&&&&&&&&&&&&&&&&& s[smax]=-1;&&&&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&& if(listen(s[smax],5) 0){&&&&&&&&&&&&&&&&& close(s[smax]);&&&&&&&&&&&&&&&&& s[smax]=-1;&&&&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&& error=getnameinfo(res-ai_addr,res-ai_addrlen,hbuf,sizeof(hbuf),sbuf,sizeof(sbuf),&&&&&&&&&&&&&&&&& NI_NUMERICHOST | NI_NUMERICSERV);&&&&&&&& if(error){fprintf(stderr,”test:%s\n”,gai_strerror(error));&&&&&&&&&&& exit(1);&&&&&&&& }&&&&&&&& fprintf(stderr,”listen to %s %s \n”,hbuf,sbuf);&&&&&&&& if(s[smax]&sockmax)&&&&&&&&&& sockmax=s[smax];&&&&&&&& samx++;&&& }&&& if(smax= =0){&&&&&&&& fprintf(stderr,”test:no socket to listen to\n”);&&&&&&&& exit(1);&&& }&&& FD_ZERO(&rfd0);&&& for(i=0;i&i++)&&&&&&&& FD_SET(s[i],&rfd0);&&&& while(l){&&&&&&&& rfd=rfd0;&&&&&&&& n=select(sockmax+1,&frd,NULL,NULL,NULL);&&&&&&&& if(n&0){&&&&&&&&&& perror(“select”);&&&&&&&&&& exit(1);&&&&&&&& }&&&&&&&& fro(i=0;i&i++){&&&&&&&&&& if(FD_ISSET(s[i],&rfd)){&&&&&&&&&&&&&& fromlen=sizeof(from);&&&&&&&&&&&&&& ls=accept(s[i],(struct sockaddr *)&from &fromlen);&&&&&&&&&&& if(ls&0)&&&&&&&&&&&&& write(ls,”hello\n”,6);&&&&&&&&&&& close(ls);&&&&&&&&& }&&&&& }&& }}本文来自CSDN博客,转载请标明出处:}

我要回帖

更多关于 gx works2 结构化编程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信