一种仿真系统自动同步可靠通信方法与流程

文档序号:15164747发布日期:2018-08-14 17:20阅读:142来源:国知局

本发明涉及仿真系统通信技术领域,特别是涉及一种仿真系统自动同步可靠通信方法。



背景技术:

在飞行模拟器仿真、电站仿真等大型仿真系统由若干子系统组成,在子系统需要解决网络通信问题。网络通信的信息主要包括两种情况:对于周期性变化且信息状态具有连续特征的信息,可以采用周期性的数据报非可靠传输方式,如飞机位置信息;但对于信息状态具有瞬时性特征的信息,如短暂的射击状态信息,如果采用数据报非可靠传输方式在周期性发送数据包中传输,则如果数据包在传输中丢失,则在下一个传输周期到来时,飞机已由射击状态转为正常状态,射击状态将不可能为其它子系统收到。类似此类的具有瞬时性特征的仿真实体的状态信息,应该与具有连续特征的仿真实体的状态信息分开,采用可靠传输方式进行传输。此外,例如控制台对仿真实体的状态进行配置等仿真管理信息,属于事件型信息,更适合于采用可靠传输方式。

目前在仿真系统中普遍采用的可靠传输方式是采用TCP协议。这种方式使用不够方便,主要表现在以下几个方面:一是TCP传输是面向字节流的,在发送端发送的若干数据包是连接在一起一个流的形式传输,因而在接收端必须由用户识别出的数据包的边界;二是TCP传输是面向连接的,在传输前需要首先建立连接;三是仿真系统内的各子系统是自主运行的,在运行中某个或某些子系统可能会重新启动,此时TCP传输无法恢复上次运行时的通信连接,使通信无法进行。本发明给出了一种解决以上问题的方法。



技术实现要素:

本发明的目的是公开一种仿真系统自动同步可靠通信方法,将网络通信代码封装到一个类中,使仿真系统内的各子系统可以通过该类的对象来方便地实现可靠通信;这种可靠通信使得数据包只被接收一次,既不会出现重复接收、接收不到、也不会乱序;它具有TCP传输的可靠性,又克服了TCP传输需要在接收端进行数据包识别的缺点;它不需要像TCP传输那样进行通信连接;因为仿真系统内的各子系统是自主运行的,在运行中某个或某些子系统可能会重新启动,因此其上次运行时的通信关系需要恢复,本发明采用自动同步方法来满足这种需求。

本发明所述的一种仿真系统自动同步可靠通信方法,其技术解决方案如下:

包括若干台通过以太网连接的计算机成为主机,每台主机上运行一个或多个进程,其特征在于, 包括一个类UdpLink;相互通信的两个进程通过在各自的进程空间内创建两个互相匹配的所述类UdpLink的对象进行通信;所述匹配由这两个对象的初始化参数来保证;所述两个对象在所述进程间建立起一个逻辑通信信道;相互通信的两个进程使用各自对象的Send操作发送数据、使用第一对象的Recv操作接收数据;所述类UdpLink的对象具有自动同步功能,即当所述相互通信的两个进程或其中之一重新启动后,两个进程之间仍可继续实现通信;一个进程可以通过所述类UdpLink的N个对象与一个或多个其它进程建立起N个逻辑通信信道,N>1为正整数。

本发明所述的一种仿真系统自动同步可靠通信方法,其特征在于,所述类UdpLink实现如下构造函数:

UdpLink(const char *localIp, unsigned short localPort,const char *remoteIp, unsigned short remotePort);

其中,localIp是本地ip地址,十进制点字符串标准格式;localPort是本地端口号,以主机序表示;remoteIp是远程ip地址,十进制点字符串标准格式;remotePort是本地端口号,以主机序表示;与localIp,localPort,remoteIp, remotePort等价的信息被存储;被存储的与localIp和localPort等价的信息表示为(localIp,localPort);被存储的与remoteIp和remotePort等价的信息表示为(remoteIp,remotePort)。

本发明所述的一种仿真系统自动同步可靠通信方法,其特征在于,所述匹配由这两个对象的初始化参数来保证的具体做法是:

1) 第一进程创建的所述类UdpLink的第一对象按如下形式调用所述构造函数完成初始化操作:UdpLink(第一进程所在的主机上配置的第一ip地址,第一端口号,第二进程所在的主机上配置的第二ip地址,第二端口号);

2) 第二进程创建的所述类UdpLink的第二对象按如下形式调用所述构造函数完成初始化操作:UdpLink(第二进程所在的主机上配置的第二ip地址,第二端口号,第一进程所在的主机上配置的第一ip地址,第一端口号)。

本发明所述的一种仿真系统自动同步可靠通信方法,其特征在于,所述类UdpLink的每个对象包括一个发送队列、一个接收队列。

本发明所述的一种基于UDP协议的自动同步可靠通信方法,其特征在于,所述类UdpLink维持一个后台线程,该线程负责驱动一个进程内的所述类UdpLink的每个对象完成如下操作:

1)从(localIp, localPort)向(remoteIp, remotePort)发送位于所述发送队列队首数据包,并在队首数据包被成功接收后从所述发送队列中删除该队首数据包;

2)从(localIp, localPort)接收发给该对象的数据包,并把有效数据包加入接收队列队尾;所述有效数据包是指确保按序接收一次且只接收一次的数据包;

3) 实现所述自动同步功能。

本发明所述的一种仿真系统自动同步可靠通信方法,其特征在于,所述自动同步功能的实现方法如下:

1)所述类UdpLink在硬盘上维持一个自动同步文件,所述自动同步文件存储一个计数值,以下称硬盘同步计数,初值为1;

2)所述类UdpLink维持一个静态数据成员,称为本地自动同步计数,初值为0;

3)所述类UdpLink维持一个数据成员,称为远程自动同步计数,初值为0;

4)当且仅当进程在每次启动后创建所述类UdpLink的首个对象时,所述类UdpLink读取所述自动同步文件中存储的硬盘同步计数到所述本地自动同步计数;然后,所述自动同步文件中的硬盘同步计数加1;

5)所述类UdpLink的每个对象被创建后,发送同步数据包,直到接收到同步应答数据包;取出同步应答数据包中的所述本地自动同步计数,并存于所述远程自动同步计数;

6)所述类UdpLink的每个对象接收到同步数据包后,如果该同步数据包包含的所述本地自动同步计数比所述远程自动同步计数小,执行如下操作,否则忽略该同步数据包:

a)清空所述发送队列和所述接收队列;

b)置发送计数和接收计数为0;

c)置所述远程自动同步计数为同步数据包包含的所述本地自动同步计数;

d)发同步应答数据包,该同步应答数据包包含该对象的所述本地自动同步计数。

本发明所述的一种仿真系统自动同步可靠通信方法,其特征在于,所述类UdpLink的Send操作负责生成数据包并把数据包添加到所述发送队列队尾;所述类UdpLink的Recv操作负责获取所述接收队列的队首数据包,并删除该队首数据包。

本发明的积极效果在于:将网络通信代码封装到一个类中,使仿真系统内的各子系统可以通过该类的对象来实现可靠通信,使用方便。确保数据包只被接收一次,既不会出现重复接收、接收不到、也不会乱序,特别适合于在仿真系统内部传输条件设置信息、仿真对象瞬时发生的状态变化信息,这种瞬时变化信息不适合采用数据报周期传输方式,它常常造成瞬时变化信丢失;具有TCP传输的可靠性,又克服了TCP传输需要在接收端进行数据包识别的缺点,它不需要像TCP传输那样进行通信连接,使用起来更方便。四、仿真系统内的各子系统是自主运行的,在运行中某个或某些子系统可能会重新启动,因此其上次运行时的通信关系需要恢复,本发明采用自动同步方法以满足这种需求。

附图说明

图1是仿真系统通信结构。

具体实施方式

下面结合本发明的一个较佳实施例来对本发明作进一步说明。

实施例1

根据图1所示,本发明包括若干台通过以太网连接的计算机(成为主机),每台主机上运行一个或多个进程,其特征在于, 包括一个类UdpLink;相互通信的两个进程通过在各自的进程空间内创建两个互相匹配的所述类UdpLink的对象进行通信;所述匹配由这两个对象的初始化参数来保证;所述两个对象在所述进程间建立起一个逻辑通信信道;相互通信的两个进程使用各自对象的Send操作发送数据、使用第一对象的Recv操作接收数据;所述类UdpLink的对象具有自动同步功能,即当所述相互通信的两个进程或其中之一重新启动后,两个进程之间仍可继续实现通信;一个进程可以通过所述类UdpLink的N(N>1)个对象与一个或多个其它进程建立起N个逻辑通信信道。

所述类UdpLink实现如下构造函数:

UdpLink(const char *localIp, unsigned short localPort,const char *remoteIp, unsigned short remotePort);

其中,localIp是本地ip地址,十进制点字符串标准格式;localPort是本地端口号,以主机序表示;remoteIp是远程ip地址,十进制点字符串标准格式;remotePort是本地端口号,以主机序表示;与localIp,localPort,remoteIp, remotePort等价的信息被存储;被存储的与localIp和localPort等价的信息表示为(localIp,localPort);被存储的与remoteIp和remotePort等价的信息表示为(remoteIp,remotePort)。

所述匹配由这两个对象的初始化参数来保证的具体做法是:

1) 第一进程创建的所述类UdpLink的第一对象按如下形式调用所述构造函数完成初始化操作:UdpLink(第一进程所在的主机上配置的第一ip地址,第一端口号,第二进程所在的主机上配置的第二ip地址,第二端口号);

2) 第二进程创建的所述类UdpLink的第二对象按如下形式调用所述构造函数完成初始化操作:UdpLink(第二进程所在的主机上配置的第二ip地址,第二端口号,第一进程所在的主机上配置的第一ip地址,第一端口号)。

所述类UdpLink的每个对象包括一个发送队列、一个接收队列。

所述类UdpLink维持一个后台线程,该线程负责驱动一个进程内的所述类UdpLink的每个对象完成如下操作:

1)从(localIp, localPort)向(remoteIp, remotePort)发送位于所述发送队列队首数据包,并在队首数据包被成功接收后从所述发送队列中删除该队首数据包;

2)从(localIp, localPort)接收发给该对象的数据包,并把有效数据包加入接收队列队尾;所述有效数据包是指确保按序接收一次且只接收一次的数据包;

3) 实现所述自动同步功能。

所述自动同步功能的实现方法如下:

1)所述类UdpLink在硬盘上维持一个自动同步文件,所述自动同步文件存储一个计数值,以下称硬盘同步计数,初值为1;

2)所述类UdpLink维持一个静态数据成员,称为本地自动同步计数,初值为0;

3)所述类UdpLink维持一个数据成员,称为远程自动同步计数,初值为0;

4)当且仅当进程在每次启动后创建所述类UdpLink的首个对象时,所述类UdpLink读取所述自动同步文件中存储的硬盘同步计数到所述本地自动同步计数;然后,所述自动同步文件中的硬盘同步计数加1;

5)所述类UdpLink的每个对象被创建后,发送同步数据包,直到接收到同步应答数据包;取出同步应答数据包中的所述本地自动同步计数,并存于所述远程自动同步计数;

6)所述类UdpLink的每个对象接收到同步数据包后,如果该同步数据包包含的所述本地自动同步计数比所述远程自动同步计数小,执行如下操作,否则忽略该同步数据包:

a)清空所述发送队列和所述接收队列;

b)置发送计数和接收计数为0;

c)置所述远程自动同步计数为同步数据包包含的所述本地自动同步计数;

d)发同步应答数据包,该同步应答数据包包含该对象的所述本地自动同步计数。

所述类UdpLink的Send操作负责生成数据包并把数据包添加到所述发送队列队尾;所述类UdpLink的Recv操作负责获取所述接收队列的队首数据包,并删除该队首数据包。

实施例2

根据图1所示,本发明包括若干台通过以太网连接的计算机(成为主机),每台主机上运行一个或多个进程,其特征在于, 包括一个类UdpLink;相互通信的两个进程通过在各自的进程空间内创建两个互相匹配的所述类UdpLink的对象进行通信;所述匹配由这两个对象的初始化参数来保证;所述两个对象在所述进程间建立起一个逻辑通信信道;相互通信的两个进程使用各自对象的Send操作发送数据、使用第一对象的Recv操作接收数据;所述类UdpLink的对象具有自动同步功能,即当所述相互通信的两个进程或其中之一重新启动后,两个进程之间仍可继续实现通信;一个进程可以通过所述类UdpLink的N(N>1)个对象与一个或多个其它进程建立起N个逻辑通信信道。

所述类UdpLink实现如下构造函数:

UdpLink(const char *localIp, unsigned short localPort,

const char *remoteIp, unsigned short remotePort);

其中,localIp是本地ip地址,十进制点字符串标准格式;localPort是本地端口号,以主机序表示;remoteIp是远程ip地址,十进制点字符串标准格式;remotePort是本地端口号,以主机序表示;与localIp,localPort,remoteIp, remotePort等价的信息被存储;被存储的与localIp和localPort等价的信息表示为(localIp,localPort);被存储的与remoteIp和remotePort等价的信息表示为(remoteIp,remotePort)。

所述匹配由这两个对象的初始化参数来保证的具体做法是,

a) 第一进程创建的所述类UdpLink的第一对象按如下形式调用所述构造函数完成初始化操作:

UdpLink(第一进程所在的主机上配置的第一ip地址,第一端口号,第二进程所在的主机上配置的第二ip地址,第二端口号);

b) 第二进程创建的所述类UdpLink的第二对象按如下形式调用所述构造函数完成初始化操作:

UdpLink(第二进程所在的主机上配置的第二ip地址,第二端口号,第一进程所在的主机上配置的第一ip地址,第一端口号)。

如图1所示,仿真系统内的有三个子系统进程:进程A、进程B、进程C,它们分别运行于主机A、主机B、主机C,主机A、主机B、主机C的ip地址分别为128.1.1.1、128.1.1.2、128.1.1.3。则进程A、进程B、进程C通过创建如下所述类UdpLink的对象来建立三个逻辑通信信道:

a)进程A创建所述类UdpLink的对象LinkAB、LinkAC1、LinkAC2:UdpLink LinkAB("128.1.1.1",1024, "128.1.1.2",1024);

UdpLink LinkAC1("128.1.1.1",1025, "128.1.1.3",1024);

UdpLink LinkAC2("128.1.1.1",1026, "128.1.1.3",1025);

b)进程B创建所述类UdpLink的对象LinkBA:

UdpLink LinkBA("128.1.1.2",1024, "128.1.1.1",1024);

c)进程C创建所述类UdpLink的对象LinkCA1、LinkCA2:

UdpLink LinkCA1("128.1.1.3",1024",128.1.1.1",1025);

UdpLink LinkCA2("128.1.1.3",1025,"128.1.1.1",1026);

这三个逻辑通信信道是:

a)进程A到进程B:AB;

b)进程A到进程C的第一个信道:AC1;

c)进程A到进程C的第二个信道:AC2;

所述类UdpLink的每个对象包括一个发送队列、一个接收队列。发送队列、和接收队列用于存储数据包。

在本实施例中, 发送队列的元素是struct SendHead类型数据包的指针;接收队列的元素是struct RecvPacket类型数据包的指针。这两个类型数据包及本实施例采用的其它数据包类型定义如下:

a)发送数据包头

struct SendHead

{

unsigned short size;//数据包总字节数,含本域

char type;//数据包类型

};

b) 发送数据包

struct SendPacket

unsigned short size;//数据包总字节数,含本域

char type;//数据包类型,必须为1

unsigned long recvSynCount;//接收方同步计数

unsigned long recvCount;//期望接收序号

unsigned long sendSynCount;//发送方同步计数

unsigned long sendCount;//发送序号

char data[];//用户数据

};

b)接收数据包

struct RecvPacket

unsigned short size;//数据包总字节数,含本域

char data[];//用户数据

};

c)应答数据包

struct AckPacket

unsigned short size;//数据包总字节数,含本域

char type;//数据包类型,必须为2

unsigned long recvSynCount;//接收方同步计数

unsigned long recvCount;//期望接收序号

};

c)同步数据包

struct SynPacket

unsigned short size;//数据包总字节数,含本域

char type;//数据包类型,必须为2

unsigned long synCount;//同步计数

};

d)同步应答数据包

struct AckSynPacket

unsigned short size;//数据包总字节数,含本域

char type;//数据包类型,必须为3

unsigned long synCount;//同步计数

unsigned long ackSynCount;//应答同步计数

};

所述类UdpLink定义有如下数据成员:

a)本地套接字

SOCKET m_sock;

b)远程ip地址,以二进制网络序表示;

unsigned long m_remoteIp;

c)远程端口号,以网络序表示;

unsigned short m_remotePort;

d)发送计数

unsigned long m_sendCount;

e)发送队列

std::vector<struct SendHead*> m_sendPackets;

f)接收计数

unsigned long m_recvCount;

g)接收队列

std::vector<struct RecvPacket*> m_recvPackets;

h)远程自动同步计数

unsigned long m_recvSynCount; //初值为(0)

所述类UdpLink还定义有如下静态数据成员:

a)本地自动同步计数

unsigned long ms_sendSynCount; //初值为(0)

b)类UdpLink对象的指针的集合

std::vector<UdpLink*> ms_allLinks;

所述类UdpLink还定义有一个静态线程函数:

void Update();

所述类UdpLink在硬盘上维持一个自动同步文件,所述自动同步文件存储一个计数值,以下称硬盘同步计数,初值为1;

所述类UdpLink的构造函数:

UdpLink(const char *localIp, unsigned short localPort,

const char *remoteIp, unsigned short remotePort);

具体执行如下初始化操作:

步骤1,创建UDP本地套接字m_sock;

步骤2,将m_sock本地套接字bind到本地ip地址localIp和本地端口号localPort;

步骤3,将远程ip地址remoteIp转换为二进制网络序表示并存储于m_remoteIp,将远程端口号remotePort转换为网络序表示并存储于m_remotePort;

步骤4,m_sendCount置0;m_sendPackets置空;m_recvCount置0;m_recvPackets置空;m_recvSynCount置0;

步骤5,若ms_allLinks为空,则执行:

步骤5.1,从自动同步文件中读取硬盘同步计数到ms_sendSynCount;硬盘同步计数加1,若硬盘同步计数加1后回0则置硬盘同步计数为1;硬盘同步计数写回自动同步文件,关闭自动同步文件;

步骤5.2,创建以Update函数为线程执行函数的线程;

步骤6,生成自动同步数据包:

p=new struct SynPacket;

p->size=sizeof(struct SynPacket);

p->type =2;

p-> synCount= ms_sendSynCount;

将p添加到m_sendPackets队尾;

步骤7,将本对象的指针(this)加入ms_allLinks;

步骤8,操作结束;

所述类UdpLink维持一个后台线程,该线程在上述步骤5.2中创建。该线程以Update函数为线程执行函数, Update函数负责驱动一个进程内的所述类UdpLink的每个对象完成如下操作:

a)从(localIp, localPort)向(remoteIp, remotePort)发送位于所述发送队列队首数据包,并在队首数据包被成功接收后从所述发送队列中删除该队首数据包;

b)从(localIp, localPort)接收发给该对象的数据包,并把有效数据包加入接收队列队尾;所述有效数据包是指确保按序接收一次且只接收一次的数据包;

c) 实现所述自动同步功能,方法如下:

c.1)所述类UdpLink的每个对象被创建后,发送同步数据包,直到接收到同步应答数据包;取出同步应答数据包中的所述本地自动同步计数,并存于所述远程自动同步计数;

c.2)所述类UdpLink的每个对象接收到同步数据包后,如果该同步数据包包含的所述本地自动同步计数比所述远程自动同步计数小,执行如下操作,否则忽略该同步数据包:

c.2.1)清空所述发送队列和所述接收队列;

c.2.2)置所述发送计数和所述接收计数为0;

c.2.3)置所述远程自动同步计数为同步数据包包含的所述本地自动同步计数;

c.2.4)发同步应答数据包,该同步应答数据包包含该对象的所述本地自动同步计数。。

基于以上分析,可以得到Update函数的详细算法如下:

步骤1,定义数据包接收区buf,buf表示其首地址,为指向struct SendHead

类型的指针;

步骤2,取ms_allLinks中的下一个link(若到达集合中最后一个元素则返回到第一个元素),执行:

步骤2.1,从link->m_sock接收数据并存储到buf;

步骤2.2, 若数据包的发送者不是 (link-> m_remoteIp, link-> m_remotePort),转步骤2;

步骤2.3,若buf-> type为1,则数据包为发送数据包,转换buf到struct SendPacket类型;

步骤2.3.1,若buf-> sendSynCount!= m_recvSynCount,转步骤2;

步骤2.3.2,若m_sendPackets为空,转步骤2.3.7;

步骤2.3.3,取m_sendPackets的首元素hd;

步骤2.3.4,若hd->type为2,则hd为同步数据包, 转步骤2.3.7;

步骤2.3.5,转换hd为struct SendPacket 类型;

步骤2.3.6,若buf->recvSynCount==hd-> sendSynCount,且

buf->recvCount==hd-> sendCount,则

从m_sendPackets移除hd,并释放hd占用的内存;

步骤2.3.7,发送应答数据包ack:

若m_sendPackets为非空,且m_sendPackets的首元素hd的type为1,则执行:

hd-> recvSynCount= ms_sendSynCount;

hd->recvCount=m_recvCount;

否则执行:

ack. size=sizeof(struct AckPacket);

ack. size=2;

ack. recvSynCount=ms_sendSynCount;

ack.recvCount=m_recvCount;

从m_sock向(m_remoteIp, m_remotePort)发送ack;

步骤2.3.8,若buf-> m_sendSynCount!= m_recvSynCount,或

buf-> m_sendCount!= m_recvCount,转步骤2;

步骤2.3.9,申请内存:p= (struct RecvPacket*)new char[sizeof(struct RecvPacket)+ buf->size- sizeof(struct SendPacket)];

步骤2.3.10,p->size= sizeof(struct RecvPacket)+ buf->size- sizeof(struct SendPacket);

步骤2.3.11,从buf->data拷贝buf->size- sizeof(struct SendPacket)个字节到p->data;

步骤2.3.12,转步骤2;

步骤2.4,若buf-> type为2,则数据包为同步数据包,执行如下同步操作:

步骤2.4.1,清空m_sendPackets和m_recvPackets;

步骤2.4.2,置m_sendCount和m_recvCount为0;

步骤2.4.3,置m_recvSynCount为buf-> synCount;

步骤2.4.4,发同步应答数据包ackSyn SynPacket:

ackSyn SynPacket. size=sizeof(struct AckSynPacket);

ackSyn SynPacket. size=3;

ackSyn SynPacket. ackSynCount =ms_sendSynCount;

ackSyn SynPacket. synCount =buf-> synCount;

从m_sock向(m_remoteIp, m_remotePort)发送ackSyn SynPacket;

步骤2.5,转步骤2。

所述类UdpLink还实现如下发送函数Send:

int Send(void *buf,int size);

其中,buf为发送的用户数据,size(大于0)为用户数据的字节数;返回值大于0,表示成功发送的字节数;返回值小于0,表示发送失败;

所述发送函数Send执行如下操作:

步骤1,申请数据包内存:

p=new char[sizeof(struct SendPacket)+size];

若p=NULL,返回(-1),操作结束;

步骤2,置数据包头:

p->size=sizeof(struct SendPacket)+size;

p->type=1;

p->recvSynCount=0;

p-> recvCount=0;

p-> sendSynCount = ms_sendSynCount;

p-> sendCount = m_ sendCount;

m_ sendCount++;

步骤3,拷贝数据: 从buf中拷贝size个字节的数据到p->data;

步骤4,将p添加到m_sendPackets队尾, 返回size值,操作结束;

所述类UdpLink还实现如下接收函数Recv:

int Recv(void *buf,int size);

其中,buf为接收数据缓冲区,size(大于0)为接收数据缓冲区的字节数;返回值大于0, 表示成功接收的字节数;返回值等于0,表示收到同步数据包;返回值小于0, 表示无数据到达,接收失败;

所述发送函数Recv执行如下操作:

步骤1,m_recvPackets为空,返回(-1),操作结束;

步骤2,移除m_recvPackets的队首数据包到struct RecvPacket类型指针p;

步骤3,拷贝数据:将总共p->size字节的数据拷贝到buf;

步骤4,释放p指向的内存, 返回size值, 操作结束。

当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1