AIS接收数据程序.docx
《AIS接收数据程序.docx》由会员分享,可在线阅读,更多相关《AIS接收数据程序.docx(15页珍藏版)》请在冰豆网上搜索。
![AIS接收数据程序.docx](https://file1.bdocx.com/fileroot1/2022-12/17/4cacb632-e864-4a15-a183-381c371652a2/4cacb632-e864-4a15-a183-381c371652a21.gif)
AIS接收数据程序
AIS数据接收程序
唐存宝交通信息工程及控制3250
一设计目的:
实现AIS经由网络传输的数据接收,并显示在MFC的控件内;同时,为了模仿AIS数据发送的方式,简单设计了AIS发送数据的客户端。
二设计意义:
显示解码前的AIS信息,对AIS信息解码,AIS数据库编程打下根基。
可以
对这些数据进行数理统计,发现其规律,从而更好掌握AIS水域交通流状况。
三基础简介
(1)网络编程基础知识
1通信协议:
TCP/UDP/IP协议,一般称为TCP/IP协议。
UDP是用户数据报协议,该协议通信时并不建立可靠的连接,所以不能保
证数据能否达到,也不知道在什么时间到达,也不能保证数据完整性(即在传输过程中有可能丢失数据);在接收方,数据有可能次序改变,也有可能重复收到一条数据。
TCP是传输控制协议,这是网络应用程序首要的协议。
它是一个大块数据
无差错输送的协议,即使传输的数据报是以错误的次序到达的,TCP协议却能使数据报按发送的次序重新组合。
它包括了HTTP,FTP这两种协议。
TCP协议建立了一个在两台计算机之间全双工、点对点的连接。
这种连接的每一个端上的程序都使用它自己的端口。
IP地址和端口号组合称为一个套接字。
总之,TCP协议在通信双方间建立了一条可靠,无数据差错,无数据重复的连接。
当然,这不
需要我们来完成,由计算机自己来完成。
UDP和TCP协议相比,UDP通信会比TCP通信快些,因为UDP通信双方不需要建立连接;而TCP需要建立可靠的连接,因此在一个庞大的聊天室中用UDP协议也未尝不可。
但是,对于不容许丢失的数据、非常重要的数据,一般
采用TCP协议。
2套接字
IP地和端口号组合成一个套接字。
好比用固定电话通信一样,要想打电话,你必须有电话机(相当于你有IP),有个电话机,但你还不知道跟哪一部电话通讯,好了,电话号码就指明了我们通讯的电话,也就相当于端口指明了要和我们通信的应用程序。
否则,一台电脑上的那么多网络应用程序,谁知道哪一个程序
会负责数据的收发工作?
电话机和端口就组成了的套接字。
好了,有了电话机,应使它处于正常工作状态,也就是侦听状态,以便别人
打来电话时,我们能接收。
在服务器应用程序上应有一套接字处于侦听状态,以
使客户机一有数据请求便能侦听到。
基于TCP的流式套接字,不仅要有侦听套
接字,而且有连接(通讯)套接字以保证可靠连接。
当然,基于UDP的,就不
需要这种连接套接字了。
3异步非阻塞通讯和同步阻塞通讯
假如有一接收数据的函数,若没有数据到来,它一直等待,其它函数在此时
1
无法执行。
直至时此函数接收到数据,它才返回。
这样的通信方式就是阻塞的,
同时也是同步的(毕竟你必须等待它执行完嘛!
)。
假如一接收数据函数,有没有数据到来,它立即返回,这就是异步非阻塞方式了。
好比一个体育老师测试100名学生400米的成绩,他可以有两种方式来测试:
一种方式是:
先让第一个学生跑,等跑完后记录时间,再让下一个跑,好了,它跑的过程中,你必须等待,这就是同步;同时,其它同学在这个时间不能跑,这
就是阻塞。
另一种办法是:
先让第一个同学跑,10秒再跑一个,再过10秒又跑一个,这样不用等一个同学跑完又有同学跑,这就是异步,这种方式在一个学生跑时其它学生也不阻挡其它学生跑,这就是非阻塞。
4MFC类(具体是CAsyncSocket,CSocket)屏蔽了TCP/IP的细节,屏蔽了异步同步,阻塞非阻塞的实现细节,对于初学网络编程的可以方便快捷开发网络应
用程序。
如果要想了解同步、异步、阻塞与非阻塞等,最好还是用WinSockAPI函数来编程。
事实上,CAsyncSocket,CSocket就是WinSockAPI的良好封装。
CSocket是内载了多线程的机制,不信的话你可以设计一个单击按纽,一旦
单击这个按纽就弹出一个模态的消息框。
你在数据接收时,点击按纽,消息框弹
出,但是接收数据的函数却仍然执行,这就至少说明了两点:
CSocket是阻塞的;
CSocket类的数据收发实际开辟了另一线程。
实际上,一个CSocket类及其派生
类的对象中有一个套接字窗口句柄。
CSocketWnd各种的网络事件都是由此窗口
自发调用的。
(2)AIS有关介绍
AIS是工作在VHF海上移动频段,其工作频率为161.975MHz和
162.025MHz。
它是通过自组织时分多址接入(SOTDMA)的通信协议方式自主地向外播发船舶的静态与动态信息。
AIS能够实现船舶、船岸间的船舶标识、位置、航向、航速等航行信息的自动交换,是新一代的海上通信导航系统。
安装有AIS的船舶发送的AIS静态、动态和与航次有关的信息内容如表1所示。
AIS输出的主要信息的信息种类如表2所示PP。
表1船舶发送的
AIS信息
静态的
动态的
与航次有关的
海上移动服务识别
具有精度指示和完整状态的船
船舶吃水
(MMSI)
舶位置
呼号和船名
以协调世界时(UTC)标记的定
危险货物(种类)
位时间
IMO编号
对地航向(COG)
目的港和ETA
船长和船宽
对地航速(SOG)
航线计划(转向点)
船舶类型
航行状态
定位天线的位置
旋回速率(ROT)
表2AIS主要信息的结构和种类
信息ID码
信息名称
信息描述
1
船位报告
定时船位报告
2
船位报告
分配定时船位报告
3
船位报告
讯问船位报告
4
基站报告
基站目前的位置、时间、时隙
5
静态和航行相关数据
定时静态和航行相关数据报告
2
9
标准搜救飞行器位置报告
参与搜救的飞行器位置报告
10
UTC/日期响应
输出有效的UTC/日期
11
申请安全相关信息
安全相关数据通信
12
安全相关确认
接收到安全相关数据的确认
13
安全相关的广播信息
与安全有关的广播通信
AIS船舶信息服务系统的组成由三个部分组成,首先,设在各地的AIS接收机接收船舶自主发送的AIS有关表1所列的AIS信息;其次,将接收到的AIS
数据信息进行协议转换处理后数据信息不断地通过互联网络传输到(PUSH)数
据中心的数据服务器中;最后,在数据服务器中将AIS数据信息进行解码后,
在ECDIS上显示出相关的AIS信息,并向客户端发布。
基于ECDIS的AIS船舶信息服务系统的组成框架如图1所示。
图2为数据传输的关键技术。
天线
天线
天线
位置1
位置2
位置n
AIS接收机
AIS接收机
AIS接收机
数据协议转换处理
数据协议转换处理
数据协议转换处理
INTERNET
数据服务器
INTERNETINTERNET
客户端1客户端2客户端n
图1基于ECDIS的AIS船舶信息服务系统的组成框架图
RS232
TCP/IP网络
AIS接收机
RS232到TCP/IP协议转换器
波特率38400bit/s
网络参数设置
服务器
IP地址:
192.168.1.120
掩码:
255.255.255.0
网关:
192.168.1.1
图2远程采集AIS数据信息系统框图
如图2所示,从AIS接收机到数据服务器传输链路主要分为两个部分。
四设计思想
从AIS的介绍中明显可以看出,要设计的程序实际是收集各地AIS的数据信息服务器,不是客户端。
用CSocket派生类实现AIS数据接收服务器程序。
CAsyncSocket,CSocket
3
为支持异步非阻塞方式,提供了网络事件NetworkEvents。
如侦听套接字A侦听到连接请求,侦听套接字A会收到一个OnAccept事件,到这个事件里,你应该调用virtualBOOLAccept(CAsyncSocket&rConnectedSocket,SOCKADDR*lpSockAddr=NULL,int*lpSockAddrLen=NULL)来实现建立连接套接字rConnectedSocket(设为B)。
数据到来时,连接套接字B会收到OnRecieve事件,你可以在此事件中调
用B的virtualintReceive(void*lpBuf,intnBufLen,intnFlags=0);来接收数据放到lpBuf中,你可以在此时把lpBuf显示在编辑框里。
在连接中,如遇到网络中断或对方客户端(AIS)关闭了连接套接字,那么B会收到一个OnClose事件,在此事件里你可以调用B.Colse();实现B套接字的关闭,释放其它的资源;最为重要的是,AIS好像移动电台一样,安放的位置一般船舶密度很大,这也就是说传输的数据量很大,把这些数据动态显示在编辑框的框架内可以看到明
显的数据在闪烁,在这种情况下为了看清数据,设置了停止监听按纽。
上面已经说了,CSocket是内载了多线程机制、提供同步阻塞调用的类。
停止监听不算很容易,不仅涉及到一些通信难理解的概念,还有处理内载线程和主
线程之间的交互问题。
有两种解决办法,一个是基于MFC提供的CSocket成员函数(面向对象),另一种是根据算法来终止监听(面向过程)。
为了避开CSocket类中比较难理解的函数,本程序选择了一个算法实现了监听的停止。
对于AIS模拟客户端程序,不是主要任务。
故从简设计。
其主要作用就是为了模拟AIS的数据发送。
其主要原理就是定义了一个定时器,在很短的时间内
投递并响应WM_TIMER消息,在这个消息响应的函数中,调用了Send函数,因为时间超时设置的较短,故Send执行次数相当多;再者,Send发送的数据,类似于船用AIS发的数据,为了区别,已在各条消息上标上序号。
这也就生动
模拟了船上发送的AIS信息。
但是,限于时间,此客户端功能极少,仅提供AIS类似的数据格式,AIS数据量大之作用,其它作用不具备了。
对于AIS如先启用AIS.exe,再启用AISCliemt.exe,点相关内容参见注意事项。
五实现步骤
1、利用MFCappwizard向导建立一个基于对话框程序;注意在第三步是时选中windowsSocket。
以加载套接字库资源。
如下图3
图3建立工程时选择WindowsSockets
4
2、生成后添加控件,控件有
控件类型
控件ID
控件文本
控件属性
处理
Statictext
IDC_STATIC_PORT
端口号为8000
默认
关联CStatic变量
Statictext
IDC_STATIC_IP
对方IP:
默认
EditBox
IDC_EDIT_RECEIVE
勾选Multiline
关联CEdit变量
Button
IDC_BTN_HOSTIPNAME
本地主机和IP
消息响应
Button
IDC_BTN_LISTEN
开始监听
勾选Disabled
消息响应
Button
IDC_BTN_STOPLISTEN
停止监听
勾选Disabled
消息响应
Button
IDC_BTN_CLEARDATA
清除数据
勾选Disabled
消息响应
3、定义一个CSocket派生类CLisSocket.添加CAISDlg*的一个数据成员和OnAccept(),OnReceive(),OnClose()事件响应函数,并添加得到CAISDlg*一个函数voidSetParent(CAISDlg*)使套接字得到CAISDlg*成员。
具体代码如下:
voidCLisSocket:
:
OnAccept(intnErrorCode)
{//TODO:
Addyourspecializedcodehereand/orcallthebaseclassCSocket:
:
OnAccept(nErrorCode);
m_pDlg->OnAccept();//使OnAccept事件交由主对话框来处理;
}
voidCLisSocket:
:
SetParent(CAISDlg*Dlg)//得到主对话框指针m_pDlg;
{
m_pDlg=Dlg;
}
voidCLisSocket:
:
OnClose(intnErrorCode)
{//TODO:
Addyourspecializedcodehereand/orcallthebaseclass
CSocket:
:
OnClose(nErrorCode);
Close();//对方关闭套接字或网络中断时响应;此时套接字已调用了Close()函
数,即通讯套接字将不存在,不具有断后自动重新接收数据的功能
}
voidCLisSocket:
:
OnReceive(intnErrorCode)//有数据到来时响应,转m_pDlg->OnReceive();
{
//TODO:
Addyourspecializedcodehereand/orcallthebaseclassCSocket:
:
OnReceive(nErrorCode);
if(bStop==false)//bStop是在AISDlg.cpp中定义的全局变量,目的
//是根据BOOLbStop的值来决定是不是接收数据,想停止监听时只需设置bStop为true即
可。
{
m_pDlg->OnReceive();
}
4、插入一个新端口对话框。
CPortDlg,设置端口;并在CAISDlg:
:
OnInitDialog()
中初始化。
向CAISDlg中增加CStringstrText,intm_nPort。
strText用来提供编辑框上显示的接收到的字符,也是本程序解码的唯一接口。
m_nPort是保存端口设置对话框中所设置的值。
BOOLCAISDlg:
:
OnInitDialog()
{
5
CDialog:
:
OnInitDialog();
//Add"About..."menuitemtosystemmenu.
//IDM_ABOUTBOXmustbeinthesystemcommandrange.ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX<0xF000);
CMenu*pSysMenu=GetSystemMenu(FALSE);if(pSysMenu!
=NULL)
{
CStringstrAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if(!
strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,
strAboutMenu);
}
}
//Settheiconforthisdialog.Theframeworkdoesthisautomatically
//whentheapplication'smainwindowisnotadialog
SetIcon(m_hIcon,TRUE);//Setbigicon
SetIcon(m_hIcon,FALSE);//Setsmallicon
//TODO:
Addextrainitializationhere
//初始化成员并设置端口号
strText="";
m_sClientIP="";
CPortDlgdlg;
m_Port=8000;
if(dlg.DoModal()==IDOK)
{
m_Port=dlg.m_nPort;
CStringstr;
str.Format("端口号为%d",m_Port);
m_cPort.SetWindowText(str);
}
returnTRUE;//returnTRUEunlessyousetthefocustoacontrol
}
5、在CAISDlg中添加成员侦听套接字和连接套接字,添加OnAccept(),OnReceive(),
OnClose()以在侦听套接字得到网络事件时转移给对话框来处理。
添加voidInit()来初始化成
员,添加voidDisplayData()把数据显示在编辑框内。
代码如下:
voidCAISDlg:
:
OnAccept()
{
6
CStringstr;
SOCKADDR_INaddr;
intlen=sizeof(sockaddr);
m_listen.Accept(m_connect,(sockaddr*)(&addr),&len);//连接请求到来时获得对方IP。
m_sClientIP=inet_ntoa(addr.sin_addr);
charIP[50];
strcpy(IP,m_sClientIP);
str.Format("成功建立连接,对方IP:
%s",IP);
GetDlgItem(IDC_STATIC_IP)->SetWindowText(str);
//MessageBox("接收数据成功");
}
voidCAISDlg:
:
OnReceive()//信息到来时调用,实现数据的接收的关键部分
{
char*pBuf=newchar[1025];
intlen=1024;
intnReceived;
CStringstrReceived;
nReceived=m_connect.Receive(pBuf,len);
if(nReceived!
=SOCKET_ERROR)
{
//MessageBox("停息成功接收");pBuf[nReceived]=NULL;strReceived=pBuf;
deletepBuf;
strText="\r\n"+strReceived+strText;
DisplayData();//显示数据
}
voidCAISDlg:
:
Init()//初始化套接字
{
m_connect.SetParent(this);
m_listen.SetParent(this);
m_listen.Create(m_Port);
}
voidCAISDlg:
:
DisplayData()
{
if(strText.GetLength()<2000)//显示数据的编辑框有限,strText过大没有意义
{
m_cRecv.SetWindowText(strText);
7
UpdateData(false);
}
else
{
strText.Left(2000);
m_cRecv.SetWindowText(strText);
UpdateData(false);
}
}
6、停止监听和清除数据。
刚才已经讲过,接收数据要在bStop为false情况下,那么单
击了“停止监听”按纽后,根据下列代码,bStop为true,将不在接收数据。
同时删除了监
听和连接套接字资源。
voidCAISDlg:
:
OnBtnStoplisten()
{
//TODO:
AddyourcontrolnotificationhandlercodehereGetDlgItem(IDC_BTN_CLEARDATA)->EnableWindow(true);GetDlgItem(IDC_BTN_LISTEN)->EnableWindow(true);GetDlgItem(IDC_BTN_STOPLISTEN)->EnableWindow(false);
CStringstr;
str.Format("已断开同客户IP:
%s的连接",m_sClientIP);
GetDlgItem(IDC_STATIC_IP)->SetWindowText(str);
bStop=true;
m_listen.Close();
m_connect.Close();
}
六程序功能演示
仅提供在一台计算机上演示方法
1、用模拟客户端AISClient.exe测试
运行AIS.exe,在输入端口对话框中设置端口,比如8000,点击确定。
点击开始监听。
运行AISClient,点“击连接服务器”。
会出现图4状态。
客户端和服务器端均出现“成功建立连接字样”;服务器端上部还有与此连接的IP等字样。
此时点击客户端的自动发送,将会看到有
“!
AIVDM,1,1,,A,1P000Oh1IT1svTP2r:
43grwboEq4,0*01:
18”
字样的数据在服务器端快速大批流出;点击服务器端停止监听,对话框上部
会有“成功断开连接”的字样。
服务器端不能再点击“开始监听”。
2、用真正AIS传输过来的数据进行测试。
运行AIS.exe,在输入端口对话框中设置端口,比如8000,点击确定。
会看到图5对话框。
点击开始监听。
通过AIS设置软件设置AIS客户端的连接端口为8000,把服务器改成运行AIS.exe的IP。
点击开始监听,此时会看到如图6所示的AIS船舶信息。
点击“停止监听”,AIS数据停止接收;出现图7。
单击“清除数据”,出现图8。
此时还可以点击“开始监听”再次进行监听。
8
图4点击连接服务器后状态
图5开始监听前的AIS对话框
图6“开始监听”后的对话框
9
图7停止监听的对话框
图8点击清除数据之后的对话框
七注意事项
1、模拟客户端AISClient设计非常简单,只是提供了一种类似AIS数据的发送方式,此种发送方式在在程序内部定义了一个定时器,在很短的时间过后就发送数据。
那么AIS.exe就可以接收数据