1、移动IP编程,移动IP编程,Linux网络编程 移动IP程序设计,Linux网络编程,BSD套接字接口 网络编程基本概念 网络编程实例,BSD套接字接口,Linux支持伯克利(BSD) 套接字编程。 不仅支持各种形式的网络,而且还是一种进程间通信的机制。 一个套接字描述一个通信连接的一端,而两个通信的进程,每个进程都需要一个套接字描述。 套接字可以被看成是一种特殊的管道。,BSD套接字接口,Linux支持几种套接字,这些就是众所周知的地址族。 Linux常用套接字。 INET The Internet address family IPX Novell IPX X25 X25,BSD套接字接口
2、,套接字所支持的服务类型 1.Stream(数据流)这些套接字提供了两个方向的序列数据流,这些数据流保证在传输过程中数据不被丢失、破坏或重复。数据流套接字由Internet (INET)地址族的TCP协议所支持。,BSD套接字接口,2.Datagram(数据包)也提供两个方向上的数据传送,但不像数据流套接字,它们不提供消息到达的保证。即使到达也不保证这些数据包按照一定的顺序到达或丢失、重复。这种类型的套接字由Internet地址族的UDP协议所支持。,BSD套接字接口,3.Raw(原始)这种类型的套接字允许进程直接访问底层协议。例如,Raw Socket,以了解原始IP数据传输。,BSD套接字
3、接口,4.Reliable Delivered Sockaddrssages(可靠传递消息)非常像数据包套接字但是保证数据的到达。,BSD套接字接口,5.Sequenced Packets(顺序数据包)数据流套接字但数据包的大小固定。,BSD套接字接口,6.Packet(包)不是标准的BSD套接字类型,它是一个Linux特定的扩展,允许进程在设备层直接访问Packet。,BSD套接字接口,创建一个BSD套接字 建立一个新的套接字的系统调用将它的地址簇、套接字类型和协议传给标识符。首先,请求的地址族为了找到一个匹配的地址族被用来搜寻pops向量。它可能时一个特殊的地址族,作为内核模块而被执行。在
4、这种情况下,内核守护进程必须在我们能够继续进行之前加载模块。一个新的socket数据结构被用来表示BSD套接字。实际上,socket数据结构是VFS的inode数据结构的一部分,分配一个套接字实际上意味着分配一个VFS的inode数据结构。如果你想要对套接字的操作的方式与普通文件一样,你就不会对此感到奇怪了。由于所有的文件由VFS的inode数据结构来表示,为了支持文件操作,BSD套接字必须也能由VFS的inode数据结构来表示。,BSD套接字接口,使用套接口通信的基本过程 创建一个BSD套接字 绑定一个INET BSD套接字 连接一个INET BSD套接字 监听一个INET BSD套接字 接
5、收一个连接请求,BSD套接字接口,创建一个BSD套接字 建立一个新的套接字的系统调用将它的地址簇、套接字类型和协议标识符。 首先,请求的地址族为了找到一个匹配的地址族被用来搜寻pops向量。它可能时一个特殊的地址族,作为内核模块而被执行。在这种情况下,内核守护进程必须在我们能够继续进行之前加载模块。一个新的socket数据结构被用来表示BSD套接字。实际上,socket数据结构是VFS的inode数据结构的一部分,分配一个套接字实际上意味着分配一个VFS的inode数据结构。如果你想要对套接字的操作的方式与普通文件一样,你就不会对此感到奇怪了。由于所有的文件由VFS的inode数据结构来表示,
6、为了支持文件操作,BSD套接字必须也能由VFS的inode数据结构来表示。,BSD套接字接口,用最新方式建立的BSD的socket数据结构,包括一个指向指定套接字例程的地址族的指针,它被设置成可从pops向量重新获得的proto_ops数据结构。它的类型被设置成所请求的socket类型,如SOCK_STREAM、SOCK_DGRAM等。地址族特殊的建立例程通过使用保留在proto_ops数据结构中的地址而被调用。 一个空闲的文件描述符由当前进程的fd向量分配,它指向的file数据结构被初始化。这包括设置指向由BSD套接字接口所支持的一组BSD套接字文件操作的指针。任何未来的操作将引导套接字接口
7、,套接字接口通过调用其地址族操作例程宋依次将这些操作传给所支持的地址族。,BSD套接字接口,绑定一个INET BSD套接字为了能够侦听传入的Internet连接请求,每个服务器必须建立一个INET BSD套接字,然后用其地址将其绑定。绑定操作主要在INET套接字层内进行,INET套接字层由来自底层的TCP和UDP层所支持。已经被绑定到一个地址上的套接字不能被其他任何通信所使用,这意味着socket的状态必须是TCP_CLOSE。传给绑定操作的sockaddr包含被绑定的IP地址和一个端口号。通常被绑定的p地址应该被分配给一个网络设备,该网络设备支持INET地址族,它的接口是向上层的并能被使用。
8、通过使用ipconfig命令能够看到网络接口在系统中正处于激活状态。IP地址也可是全为1或全为0的IP广播地址。这是一些特殊的地址,它意味着发送给每个设备。如果机器作为一个透明的代理服务器或防火墙,则IP地址可以被指定为任意的IP地址,但只有具有超级用户特权的进程能被绑定到任何IP地址。被绑定的IP地址被保存在recv_addr和saddr字段中的sock数据结构中。这些IP地址使用在查找中,各个作为正发送的IP地址。端口号是有选择的,如果没有被指定,则所支持的网络将请求一个空闲的端口号。按惯例,小于1024的端口号不能被没有超级用户特权的进程使用。如果下层网络分配一个端口号,它经常大于102
9、4。,BSD套接字接口,当数据包被底层网络设备接收时,它们必须路由到正确的INET或BSD套接字以使它们能被处理。考虑这一点,UDP和TCP维护在传入的IP消息中用来查找地址的表,将它们正确写入socket/sock。TCP是一个面向协议的连接,因此处理TCP数据包的消息比处理UDP数据包的消息要多。UDP维护着分配UDP端口的表Udpash表。它是由指向sock数据结构的指针组成,这些指针由基于端口号的hash函数索引。由于UDP的hash表比允许的端口数量小的多(udp_hash的长度为128或UDP_HTABLESIZE),在表中的一些入口使用sock的next指针指向连接起来的sock
10、数据结构链。由于TCP维护几个hash表,它更加复杂。然而TCP在绑定操作过程中实际上并不增加绑定的sock数据结构到它的hash表中,它仅仅检查请求的端口号目前不被使用。在侦听操作过程中sock数据结构被加到TCP的hash表中。,BSD套接字接口,连接一个INETBSD套接字一旦建立一个套接字,如果这个套接字没有用来侦听入站连接请求,那么它能够用来建立一个出站连接请求。对于像UDP之类的无连接的协议,套接字操作不需要干多少事,而像TCP之类的面向连接的协议,套接字必须在两个应用之间建立一条虚拟电路。 一个出站连接能够建立在处于恰当状态的INET BSD套接字之上,也就是说,它没有一个已经建
11、立的连接,不能用来侦听入站连接。这意味着BSD的socket数据结构必须处于SS_UNCONNECTED状态。UDP协议在两个应用之间并不建立虚拟连接,任何发送的消息是数据包,这些消息可能到达也可能不到达目的地。然而它支持BSD的connect套接字操作。基于UDP INET BSD的套接字的连接操作仅仅建立远程应用的地址,即它的IP地址和p端口号。此外,它建立一个路由表入口缓冲,这使得基于BSD的套接与的发送的UDP包不需要再次检查路由数据库(除非路由无效)。缓冲的路由消息由INK的sock数据结构中的ip_route_cache指针所指向。如果没有给定的地址消息,这个缓冲路由和IP地址消息
12、将自动地被使用这个BSD套接字发送的消息所使用。UDP将sock的状态置为TCP_ESTABLISHED。,BSD套接字接口,对于TCP BSD套接字的连接操作,TCP必须建立一个包含连接消息的TCP消息并将它发送给指定的IP目的地。TCP消息包含关于连接、一个唯一的开始消息序列号、能够被初始化主机处理的最大尺寸的消息、传送和接收窗口的尺寸等消息。在TCP中所有的消息被编号,起始的序号被作为第一个消息号。Linux选择合理的、随机的数值以避免恶意的协议攻击。每一个被TCP连接一端发送而被另一端成功地接收的消息被确认为成功到达并没有损坏。没有确认的消息将被再次传送。传送和接收窗口的大小是可能没有
13、确认的正在发送的消息的数量。消息最大长度取决于在请求的初始端使用的网络设备。 如果接收端的网络设备支持更小的消息最大长度,那么连接将使用两者的最小值。建立出站TCP连接请求的应用必须等待目的应用接收或拒绝连接请求的响应。由于TCP的sock正期望传入的消息,它被加入tcp_listening_hash,这样传入的TCP消息能够被直接传给sock数据结构。TCP也能启动计时器,如果目的应用不对请求响应,这时出站连接请求可以因超时而被中断。,BSD套接字接口,监听一个INETBSD套接字一旦一个套接字已经有一个地址绑定给它,它可以侦听传入的指定绑定地址的连接请求。一个网络应用可以侦听一个套接字而没
14、有先绑定一个地址,在这种情况下,INET套接字层为这个协议找到一个没使用的端口号并自动地将它绑定给套接字。侦听套接字函数将套接字的状态置为TCP_LISTEN并做任何网络需要允许传入连接的特定工作。对于UDP套接字,改变套接字的状态足够,而TCP现在应增加套接字的sock数据结构到两个hash表中,此时它应处于激活状态。这些是tcp_bound_hash表和tcp_listening_hash表。它们借助基于IP端口号的hash函数来索引。,BSD套接字接口,接收一个连接请求 UDP不支持接收INET套接字连接请求的连接概念,这些连接请求仅仅应用于TCP协议用来作为关于侦听套接字的接收操作,并
15、将起初的侦听套接字复制到一个新的socket数据结构中。接收操作然后被传给所支持的协议层,在这种情况下,INET接收任何传入的连接请求。如果底层协议,如UDP不支持连接则INET协议层的接收操作将失败。否则接收操作将被传给真正的协议,在这种情况下,为TCP。接收操作要么阻塞,要么非阻塞。在非阻塞情况下,如果没有接收的传入连接,接收操作将失败,最近建立的socket数据结构将被销毁。在阻塞情况下,执行接收操作的网络应用将被添加到一个等待队列里,直到收到TCP连接请求,才结束等待。一旦已经接收包含请求的sk bufferf的连接请求被删除,sock数据结构将转向INET套接字层,这里它将被连接到早
16、些时候建立的新的sock数据结构。新的socket的文件描述符(rd)号将返回网络应用,然后应用能够在基于最近方式建立的INETBSD套接字操作中使用这些文件描述符。,BSD套接字接口,接收一个连接请求 UDP不支持接收INET套接字连接请求的连接概念,这些连接请求仅仅应用于TCP协议用来作为关于侦听套接字的接收操作,并将起初的侦听套接字复制到一个新的socket数据结构中。接收操作然后被传给所支持的协议层,在这种情况下,INET接收任何传入的连接请求。如果底层协议,如UDP不支持连接则INET协议层的接收操作将失败。否则接收操作将被传给真正的协议,在这种情况下,为TCP。接收操作要么阻塞,要
17、么非阻塞。在非阻塞情况下,如果没有接收的传入连接,接收操作将失败,最近建立的socket数据结构将被销毁。在阻塞情况下,执行接收操作的网络应用将被添加到一个等待队列里,直到收到TCP连接请求,才结束等待。一旦已经接收包含请求的sk bufferf的连接请求被删除,sock数据结构将转向INET套接字层,这里它将被连接到早些时候建立的新的sock数据结构。新的socket的文件描述符(rd)号将返回网络应用,然后应用能够在基于最近方式建立的INETBSD套接字操作中使用这些文件描述符。,网络编程基本概念,Linux采用的是BSD方式的Socket编程 面向连接 无连接的Socket,网络编程基本
18、概念,用户常用两种套接字, 数据流套接字 数据包套接字,网络编程基本概念,用户常用两种套接字, 数据流套接字 数据包套接字,网络编程基本概念,数据流套接字提供了双向的,有序的,无重复并且无记录边界的数据流服务。 数据包套接字支持双向的数据流,但并不保证是可靠,有序,无重复的。也就是说,一个从数据包套接字接收信息的进程有可能发现信息重复了,或者和发出对时顺序不同。数据包套接字的一个重要特点是它保留了记录边界。对于这一特点,数据包套接字采用了与现在许多包交换网络(例如以太网)非常类似的模型。,网络编程基本概念,客户机/服务器模式(C/S) 目前,在数据处理领域,客户/服务器(Client/Serv
19、er,简称C/S)体系结构广泛应用于各种大型计算模式中,是分布式大型计算中网络计算机的主要工作方式。 当我们谈到网络编程时,在头脑中要有一个基本概念:网络通信至少要两台计算机,基于TCP/IP的网络编程的主要结构是客户/服务器模式,当然也有其他模式,如数据广播系统就是一个非C/S模式。,网络编程基本概念,客户机/服务器模型,网络编程基本概念,客户/服务器并不是一种物理结构,而是一种软件的体系结构。 客户、服务器软件可能分别处于两台不同的机器上,也可能处于一台机器上,也可能某一时刻原来的客户变成了服务器,而服务器又变成了客户。 所以,对客户/服务器的理解应是应用程序之间相互作用的一种模式,是一种
20、软件体系结构。,网络编程基本概念,客户程序(进程)发送请求给服务器程序(进程),服务器进程对客户的请求作出响应,并产生结果。 一般来说,服务器进程完成一些较公用而又特殊的处理,如进行一些复杂的计算、大型数据库查询等。而客户进程则由于将上述一些特殊的应用交由服务器来完成,所以可以专心处理其他工作,比如:事务处理、人机交互等。 在客户/服务器模式下,客户机为主动方,即请求方:服务器方为被动方,接收请求方的请求。,网络编程基本概念,在TCP/IP应用中,客户/服务器模式是按以下方式实现。 客户一方,TCP/IP应用程序流程为:打开通信信道(申请一个套接字),并连接到服务器在主机的保留端口,该端口对应
21、服务器的TCP/IP进程;向服务器发出请求报文,等待接收应答;从服务器方收到最终应答结果,或在不再请求时关闭信道并中止客户进程。,网络编程基本概念,服务器一方,TCP/IP应用程序的流程为:打开通信信道(申请一个套接字),通知本地主机在某一保留端口接收客户请求:等待客户请求到达指定端口;接收到请求,启动一个新进程处理用户请求,同时释放就进程以便响应新的客户请求,一旦服务完成,关闭新进程与客户的通信链路;继续等待客户请求;如果想停止响应客户请求,则关闭服务器进程。,网络编程基本概念,阻塞与非阻塞 阻塞是指唤起一个函数,该函数直到相关操作完成时才返回。 在Berkeley套接字模型中,一个套接字的
22、操作的缺省行为是阻塞方式的,除非程序员显式地请求该操作为非阻塞方式。 推荐尽可能使用非阻塞方式(异步方式)的操作,只有在绝对必要的时候才采用阻塞方式。,网络编程实例,套接字有三种类型:数据流套接字、数据包套接字及原始套接字。数据流套接字定义了一种可靠的面向连接的服务,实现了无差错无重复的顺序数据传输。数据包套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。,网络编程实例,原始套接字允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。 无连接服务器一般都是面向事务处理的,一个请求一个应答就完成了客户程序与服务程序之间的相互作用。
23、 面向连接服务器处理的请求往往比较复杂,不是一来一去的请求应答所能解决的。,网络编程实例,面向连接的套接字工作过程如下: 服务器首先启动,通过调用socket()建立一个套接字,然后调用bind()将该套接字和本地网络地址联系在一起,再调用listen()使套接字做好侦听的准备,并规定它的请求队列的长度,之后就调用accept()来接收连接。 客户在建立套接字后就可调用connect()和服务器建立连接。连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据。最后,待数据传送结束后,双方调用close()关闭套接字,网络编程实例,无连接套接字应用程序流程图,
24、网络编程实例,面向连接套接字应用程序流程图,网络编程实例,面向连接套接字应用程序流程图,网络编程实例,在面向连接的通信中服务器和客户在交换数据之前先要建立一个连接。在无连接的通信中数据直接被发送。 无论哪一种方式,服务器总是最先启动,把自己绑定(Binding)在一个套接字上,然后去侦听消息。,网络编程实例,socket()bind()listen()accept()setsockopt()getsockopt()connect()sendto()recvfrom(),网络编程实例,(1)socket() socket()系统调用是为客户或服务器创建一个套接字,创建套接字的函数定义如下所示;#
25、include#includeint socket(int family, int type, int protocol),网络编程实例,family可以是AF_UNIX或AF_INET等 type可以是SOCK STREAM,它是可靠的,虽然通信速度较慢;也可以是SOCK_DGRAM,它的通信速度较快但不可靠。 如果type为SOCK_STREAM那么protocol为IPPROTO_TCP。如果type为SOCK_DGRAM那么protocol为IPPROTO_UDP。,网络编程实例,如果函数调用出错,函数将返回-1。否则将返回一个套接字描述符,我们可以在程序后面的调用中通过套接字描述符使
26、用这个套接字。 套接字创建时没有指定名字,这是绑定函数所要做的工作。,网络编程实例,(2)bind()系统调用。 bind()系统调用为没有名字的套接字分配一个名字。绑定的定义如下所示:#include#includeint bind(int sockfd, struct sockaddr *saddr, int addrlen),网络编程实例,第一个参数是一个套接字描述符。第二个参数是名字所使用的一个结构。第三个参数是此结构的大小。 通过调用bind()函数,我们为客户或服务器绑定了一个地址。如果程序是一个服务器,那么它把自己设置为侦听,然后等待连接。,网络编程实例,(3)listen()系
27、统调用。listen()系统调用被服务器所使用。它的定义如下所示:#include#includeint listen(int sockfd, int backlog);,网络编程实例,sockfd是套接字描述符。backlog是在一时间内尚未被决定是否拒绝的连接的号码。一般使用标准值5。如发生错误则返回值小于1。 如果这个调用成功,就可以接收连接了。,网络编程实例,(4)accept()系统调用。accept()调用被服务器用于接收任何从客户connee()调用所引入的消息。必须明白的是如果没有接收到连接这个函数将不返回任何值。它的定义如下所示:#include#includeint acc
28、ept(int sockfd, struct sockaddr *peeraddr, intaddrlen),网络编程实例,除peeraddr指向发出连接请求的客户的消息外,其他参数和bind()系统调用的相同。在消息引入的基础上,peeraddr所指向的结构的域被填上相应的值。,网络编程实例,(5)setsockopt()和getsockopt()系统调用。Linux所提供的socket库含有一个错误(bug)。此错误表现为我们不能为一个套接字重新启用同一个端口号,即使在正常关闭该套接字以后。例如,编写了一个服务器在一个套接字上等待的程序,服务器打开套接字并在其上侦听是没有问题的。无论如何,
29、总有一些原因(不管是正常还是非正常的结束程序)使程序需要重新启动。然而重启动后,我们就不能把它绑定在原来那个端口上了。从bind()系统调用返回的错误代码总是报告说我们在试图连接的端口已经被别的进程所绑定了。,网络编程实例,这个问题在于Linux内核在一个绑定套接字的进程结束后从不把端口标记为未用。在大多数UNIX系统中,端口可以被一个进程重复使用,甚至可以被其他进程使用。在Linux中绕开这个问题的办法是,套接字已经打开但尚未有连接的时候,用setsockopt()系统调用在其上设定选项(options)。setsockopt()调用设置选项,而getsockopt()从给定的套接字取得选项
30、。,网络编程实例,setsockopt()和getsockopt()的定义如下所示:#include#includeint getsockopt(int sockfd, int level, intnasockaddr, char *value, int *optlen)int setsockopt(int sockfd, int level, intnasockaddr, char * value, int *optlen),网络编程实例,其中,sockfd必须是一个已经打开的套接字。level是函数所使用的协议标准(protocol level)(TCP/IP协议使用IPPROTO_TCP
31、,套接字标准的选项使用SOL_SOCKET),选项的名联机帮助中有详细说明。*value指向为getsockopt()函数所获取setsockop()函数所设置,网络编程实例,(3)无连接的套接字服务器端程序源代码。#include #include #include #include #define PORT 6545#define MAX 4096,网络编程实例,char sockaddrsgMAX;main(int argc, char*argv)int sockfd, newfd;int cpid; /* childid*/struct sockaddr_inservaddr;stmc
32、t sockaddr_inclientlnfo;,网络编程实例,if(sockfd = socket(AF_INET, SOCK_STREAM, 0)0)sprintf(“Unable to create socketn“);#ifdef LINUXopt=1;len=sizeof(opt);setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,&len);#endif,网络编程实例,bzero(char*)&servaddr,sizeof(servaddr);servaddr.sin_family=AF_INET;servaddr,sin_addr.s
33、_addr=htonl(INADDR_ANY);servaddr,sin_family=htons(PORT);,网络编程实例,if(bind(sockfd,(structsockaddr*)&servaddr,sizeof(structsockaddr)0)sprintf(“Unable to bind socketn);for(;),网络编程实例,/*wait here*/n=recvfrom(sockfd, sockaddrsg, MAX, 0,(structsockaddr*)&clientlnfosizeof(stmctsockaddr);. ;/*do thing you want
34、 to do*/sendto(sockfd,sockaddrsg,n,0,(structsockaddr)p)&clientlnfo,sizeof(structsockaddr); ,网络编程实例,这里处理每个消息只调用了两个函数,这比面向连接的协议更容易。但你必须在同一时间处理每个消息,因为消息从多台客户向服务器涌来。而在面向连接的协议中,子进程总是知道每条消息从哪里来。 客户同样不能调用connect()系统调用。但是客户可以直接调用sendto()函数。客户机端和服务器端大致相同。只是它在调用recvfrom()之前调用sendto()。,网络编程实例,recvfrom()系统调用是这样
35、定义的:#include#include int recvfrom(intsockfd,const void*sockaddrssage_, /*the pointer to sockaddrssage*/int length, /*of sockaddrssage*/unsigned intflags, /*of routing, leave 0*/const struct sockaddr *client, /*where to send*/int length);/*of sockaddr*/,网络编程实例,(4)无连接的套接字客户端的系统调用。#include#includeint s
36、endto(int sockfd,const void *sockaddrssage_, /*the pointer to sockaddrssage*/int length, /*of sockaddrssage*/unsigned inttype, /*of routing, leave 0*/conststructsockaddr*client, /*where to send it*/ihtlength);/*of sockaddr*/,移动IP程序设计,数据格式 AGENT进程 MH进程,数据格式,struct icmp unsigned char type;unsigned cha
37、r code;unsigned short cksum;unsigned char addrnum;unsigned char addr_entry_size;unsigned short lifetime; ;struct youarehere unsigned char type; /* Type to indicate it is a Mobile serv extn. */unsigned char length; /* 6 + 4N N = the number of care of addrs*/unsigned short seqno; /* The count of adver
38、tisement messages sent */unsigned short lifetime; unsigned short flags; /* These are followed by N unsigned longs indicating* the ip address */ ;,数据格式,struct registerme unsigned char type;unsigned char flags;unsigned short lifetime;unsigned long homeaddr;unsigned long ha;unsigned long coaddr;struct
39、id Id; /* This is followed by various extensions */ ;struct regreply unsigned char type;unsigned char code;unsigned short lifetime;unsigned long homeaddr;unsigned long ha;struct id Id; /* This is followed by various extensions */ ;,AGENT进程,AGENT进程数据结构定义,typedef struct mhdunsigned long ipaddr; /* its
40、 permanent address */char authtype5; /* identifies the algorithm to be used * for authentcation */char secret64; /* secret used for authentication */int keylen; /* size of secret key */unsigned char status; /*TUNNELUP indicates we are supporting the host*/unsigned long coaddr; /* end point of tunnel
41、 */struct id RegistrationId; /* If incoming request does not contain* this value in its high 32 bits of Id,* then we have an id mismatch */ int timeleft; /* # of secs before this tunnel * is destroyed and we stop forwarding */unsigned char tunnelnum; /* tunnel number for this mh */ mhdata;,AGENT进程数据
42、结构定义,typedef struct vmhd /* AD */unsigned long ipaddr; /*IP addr of visiting mobile hostwhich is also home addr in our case*/unsigned long ha; /* Home agents addr */char authtype5; /* identifies the algorithm to be used * for authentcation */char secret64; /* secret used for authentication */int key
43、len; /* size of secret key */unsigned char status; /* reg req pending or granted */int timeleft; unsigned short fromport; /* port from which reg. request hascome and reply should be sent */struct id RegId; /* Id for the request by visiting foreign MH */ vmhdata; #endif /* _AGENT_H_ */,AGENT进程套接口建立,R
44、egreplysid = socket(AF_INET, SOCK_DGRAM, 0);WhereAmIsid = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);RegisterMesid = socket(AF_INET, SOCK_DGRAM, 0);ioctlsid = socket(AF_INET, SOCK_DGRAM, 0);RegReplyHAid = RegMeVMHid = socket(AF_INET, SOCK_DGRAM, 0); URheresid = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);,AG
45、ENT进程套接口建立,if (Regreplysid 0 | URheresid 0 | WhereAmIsid 0 | RegisterMesid 0 | RegReplyHAid 0 |ioctlsid 0) fprintf(stderr, “initsockets(): could not create sockets.n“);exit(-1);,AGENT进程套接口绑定,sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_ANY); sa.sin_port = 0; if (bind(Regreplysid, (stru
46、ct sockaddr *) ,AGENT进程套接口绑定,sa.sin_port = htons(MIPREGPORT);if (bind(RegisterMesid, (struct sockaddr *) ,AGENT进程,void cleanup() /* down all tunnels that we could have created and remove* proxy arps for all MHs we support if the arp HWaddr in* those entries is our own */int i;for (i = 0; i 1)fprintf
47、(stderr, “Done cleaning up .n“); ,AGENT进程发送代理公告,void sendURhere(struct sockaddr_in *toaddr) static struct urhmsg struct icmp icp;struct youarehere URh;unsigned long addr1; mesg;,AGENT进程发送代理公告,mesg.icp.type = ROUTERADVTYPE; /* router advertisement */mesg.icp.code = 0;mesg.icp.cksum = 0;mesg.icp.addrn
48、um = 0;mesg.icp.addr_entry_size =0;mesg.icp.lifetime = 6 ; /* 3*period of URhere mesg. */mesg.URh.type = YOUAREHERETYPE; /* Mobile serv ext */mesg.URh.length = 10; /* 6 + 4*N bytes where N is # of addresses(1) */mesg.URh.seqno = seqno+;mesg.URh.lifetime = MAXLIFETIME;mesg.URh.flags = MSRFLAG|MSHFLAG
49、|MSFFLAG; mesg.addr1 = haAddr;mesg.icp.cksum = in_cksum(u_short*),AGENT进程发送代理公告,if (sendto(URheresid, (char *) ,AGENT进程,void update_lifetimes() int i;char devname10;for (i = 1; i 1) fprintf(stderr, “n-Registration expired for %lxn“,htonl(mhinfoi.ipaddr);lowrtreq(DELRT, mhinfoi.ipaddr, ,AGENT进程,strcpy(devname,DEVICE);for(i = 1; i= supportedVMHnum; i+) if(vmhinfoi.status = 0|vmhinfoi.status = PENDING) continue;if(vmhinfoi.timeleft -=2) =0)vmhinfoi.status ,AGENT进程初始化,