2006毕业设计Delphi篇(二)
为什么叫GPRSServer?因为这个模块是和下层GPRS硬件模块通讯所用。
在这个模块中我们将和GPRS通讯的所有细节全部封装到wcomm_dll.dll动态连接库中。
这个动态链接库负责和下层具体通讯,包括UDP包的封装,下层通讯队列的维护和一些扩展功能等等。
具体代码:
Interface usesinterface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Menus, ComCtrls, ToolWin, StdCtrls, ImgList, ExtCtrls, NMUDP,winsock;
const MAX_RECEIVE_BUF=1024; //最大接收缓冲区
const MAX_SEND_BUF=1024; //最大发送缓冲区
const gprs_dll='wcomm_dll.dll';
const gprs_smm='gprs_smm.dll';
const misc='misc.dll';
type
// 用户注册信息结构
gprs_user_info=record
m_userid:array[1..12] of char; //终端模块号码
m_sin_addr:Cardinal; //终端模块进入Internet的代理主机IP地址
m_sin_port:word; //终端模块进入Internet的代理主机IP端口
m_local_addr:Cardinal; //终端模块在移动网内IP地址
m_local_port:word; //终端模块在移动网内IP端口
m_logon_date:array[1..20] of char; //终端模块登录时间
m_update_time:array[1..20] of char; //终端模块更新信息时间
m_status:byte; //终端模块状态, 1 在线 0 不在线
//m_pid:array[1..12] of char;
end;
type
//用户数据结构
data_record=record
m_userid:array[1..12] of char;
m_recv_date:array[1..20] of char;
m_data_buf:array[1..MAX_RECEIVE_BUF] of char;
m_data_len:word;
m_data_type:byte;
end;
type
Arr12 = array[1..12] of Char;
Arr16 = array[1..16] of Char;
Arr256 = array[1..256] of Char;
Arr512 = array[1..512] of Char;
Arr1024 = array[1..1024] of Char;
//下面定义的时函数类型,用于指向动态库中的函数
Function start_gprs_server()function start_gprs_server(a:HWND;b:Cardinal;c:Integer;d:PChar):Integer;stdcall;
Function start_net_service()function start_net_service(a:HWND;b:Cardinal;c:Integer;d:PChar):Integer;stdcall;
Function do_read_proc()function do_read_proc(var a:data_record;b:PChar;c:boolean):Integer;stdcall;
procedure cancel_read_block();stdcall;
Function stop_gprs_server()function stop_gprs_server(a:PChar):Integer;stdcall;
Function stop_net_service()function stop_net_service(a:PChar):Integer;stdcall;
Function do_close_all_user()function do_close_all_user(a:PChar):Integer;stdcall;
Function do_send_user_data()function do_send_user_data(a:PChar;b:PChar;c:Cardinal;d:PChar):Integer;stdcall;
Function get_user_at()function get_user_at(a:Cardinal;var b:gprs_user_info):Integer;stdcall;
Function get_max_user_amount()function get_max_user_amount:Cardinal;stdcall;
Function do_close_one_user()function do_close_one_user(a:PChar;b:PChar):Integer;stdcall;
Function SetWorkMode()function SetWorkMode(nWorkMode: integer): integer; stdcall;
Function KillProcess()function KillProcess(a:PChar):Integer;stdcall;
Function DisConnectRas()function DisConnectRas(a:PChar):Integer;stdcall;
Function GetConnEntryName()function GetConnEntryName(a:PChar):Integer;stdcall;
//The Following Function is()function is SMM
//int SMMInit(char *,int,char *,DCB *,char *,char *,int);
Function SMMInit()function SMMInit(var a:Arr16;b:Integer;var c:Arr16;var d:DCB;var e:Arr12;var f:Arr12;g:Integer):Integer;stdcall;
Function SMMFree()function SMMFree:Integer;stdcall;
Function SMMSetting()function SMMSetting(var a:Arr12;b:Integer):Integer;stdcall;
Function MakeDTUOnLine()function MakeDTUOnLine(a:Integer;var b:Arr12):Integer;stdcall;
Function SendDataToDTUBySM()function SendDataToDTUBySM(var a:Arr12;var b:Arr256;c:Integer;d:Integer):Integer;stdcall;
implementation
//gprs_dll
Function start_gprs_server()function start_gprs_server; external gprs_dll name 'start_gprs_server';
Function start_net_service()function start_net_service; external gprs_dll name 'start_net_service';
Function do_read_proc()function do_read_proc; external gprs_dll name 'do_read_proc';
procedure cancel_read_block; external gprs_dll name 'cancel_read_block';
Function stop_gprs_server()function stop_gprs_server; external gprs_dll name 'stop_gprs_server';
Function stop_net_service()function stop_net_service; external gprs_dll name 'stop_net_service';
Function do_close_all_user()function do_close_all_user;external gprs_dll name 'do_close_all_user';
Function do_send_user_data()function do_send_user_data;external gprs_dll name 'do_send_user_data';
Function get_user_at()function get_user_at;external gprs_dll name 'get_user_at';
Function get_max_user_amount()function get_max_user_amount;external gprs_dll name 'get_max_user_amount';
Function do_close_one_user()function do_close_one_user;external gprs_dll name 'do_close_one_user';
Function SetWorkMode()function SetWorkMode;external gprs_dll name 'SetWorkMode';
//gprs_smm
Function SMMInit()function SMMInit;external gprs_smm name 'SMMInit';
Function SMMFree()function SMMFree;external gprs_smm name 'SMMFree';
Function SMMSetting()function SMMSetting;external gprs_smm name 'SMMSetting';
Function MakeDTUOnLine()function MakeDTUOnLine;external gprs_smm name 'MakeDTUOnLine';
Function SendDataToDTUBySM()function SendDataToDTUBySM;external gprs_smm name 'SendDataToDTUBySM';
Function KillProcess()function KillProcess;external misc name 'KillProcess';
Function DisConnectRas()function DisConnectRas;external misc name 'DisConnectRas';
Function GetConnEntryName()function GetConnEntryName;external misc name 'GetConnEntryName';
end.
其他所用的一些动态链接库我们在这个项目中用不到。在这里我需要你们自己熟悉一下静态调用动态链接库的方法。调用动态链接库有两种方法,静态调用和动态调用,以上就是静态调用的方法。通过封装调用我们在以后的开发中就可以直接用这些函数了。
当下层硬件发送数据给我们的模块的时候我们该如何处理呢?
答案是:我们会用消息机制来处理。
处理过程为:下层数据通过UDP数据包发送到wcomm_dll.dll,我的wcomm_dll.dll就会去解析UDP数据包,并且要维护一下数据列表。最后向外广播约定好的windows消息,告诉外层程序数据已经接受到了,来取吧。
当然我的外层程序(就是我们马上要讲到的GPRSServer模块)收到了这个特定的windows消息之后,就会通过
do_read_proc函数来读取数据。do_read_proc是在wcomm_dll.dll中定义的,看看上面的代码,是不是已经定义了。
我们来看看GPRSServer是如何处理Windows消息的:
这个是消息的定义,再来看看这个消息处理函数具体做了什么工作:
var dr:data_record;
p:PChar;
bAnswer:Boolean;
begin
try
GetMem(p,1024);
if ckAnswer.Checked then
bAnswer:=true
else
bAnswer:=false;
if (do_read_proc(dr,p,bAnswer)>=0) then
begin
if dr.m_data_len=0 then
PollUserTable
else
ProcessData(dr);
end;
finally
FreeMem(p);
end;
end;
再次提醒一边,我在设计辅导的时候是不讲程序的语法的,你们要有什么不懂的地方,去查找资料!
在以上的这个函数中我们比较关心的是ProcessData()这个函数,其他函数都是一些修饰和保护等等。来看看ProcessData()这个函数的实现:
var i,j:Integer;
str,S:String;
re:Pchar;
reLong,ReLongTemp:integer;
label H1;
begin
str:=dr.m_userid+'---'+dr.m_recv_date+'---'+IntToStr(dr.m_data_len);
for i:=1 to Length(str) do
if str[i]=#0 then
str[i]:=' ';
mmDataWnd.Lines.Add(str);
mmDataWnd.Lines.Add('下位机-->通讯服务器:'+dr.m_data_buf);
/
try
re:=nil;
ReLongTemp:=0;
if dr.m_data_len>G_cachLeng then //对缓冲区进行保护
begin
fillmemory(@G_cach,G_cachLeng,$FF);
mmDataWnd.Lines.Add('缓冲区溢出!');
goto H1;
end;
re:=@dr.m_data_buf;
reLong:=dr.m_data_len;
s:='';
for j:=0 to reLong-1 do
begin
S:=S+inttohex(ord((re+j)^),2)+' ';
end;
mmDataWnd.Lines.Add('下位机-->通讯服务器:'+S+#13+#10);
if G_cachPose>=G_cachleng-1 then
G_cachPose:=0;
if reLong>(G_cachleng-G_cachPose)then
G_cachPose:=0;
move(re^,G_cach[G_cachPose],reLong);
G_cachPose:=G_cachPose+reLong;
G_reLong:=reLong;
Doit;
H1:
except
on EAccessViolation do
exit;
end;
end;
这个函数是干什么的?这个函数其实主要功能就像一个漏斗。将不断接受到的数据流存入一个叫G_cach的缓存中以供后续操作。这步很必要,因为作为UDP数据包来说你不能保证一连串的数据的完整性,而且在无限传输过程中这种不稳定性尤其突出,同学们可以用无线电传输字节流来试试,看看整个数据的真确率能不能达到70%。当缓存好了之后我们要作的事就是Doit这个函数。
看看Doit是如何实现的:
var
i,DDL:integer;
label H1;
begin
try
i:=0;
while i<G_cachLeng-1 do
begin
if (ord(G_cach[i])=$10)and(ord(G_cach[i+4])=$16) then
begin
CutReceiveData(@G_cach,G_cachPose);
fillmemory(@G_cach[i],G_cachPose,$FF);
G_cachPose:=0;
i:=i+4;
goto H1;
end else
if (ord(G_cach[i])=$68)and (ord(G_cach[i+3])=$68)and((ord(G_cach[i+ord(G_cach[i+1])+5])=$16)or(ord(G_cach[i+ord(G_cach[i+1])+5])=0) )then
begin
CutReceiveData(@G_cach,G_cachPose);
fillmemory(@G_cach[i],G_cachPose,$FF);
DDL:= ord(G_cach[i+1]);
i:=i+DDL+5;
G_cachPose:=0;
goto H1;
end;
inc(i);
end;
H1:
except
on EAccessViolation do begin
abort;
end;
end;
application.ProcessMessages;
end;
原来Doit 主要的功能是在那个G_cache里寻找完整的数据包,如果找到了就执行CutReceiveData这个函数进行真正的拆包分析。当然这个Doit是用线程来实现的。你们可能要熟悉一下线程和进程的概念。
那么CutReceiveData是作什么的呢?它是一个大的函数,主要是将101通信规约,645通信规约等等规约解析成我们需要的原始数据,比如说电量,电压,电流等等。这里涉及到商业机密在此不表述了。
当我们把这些原始数据都得到之后,就将这些数据按照与Java后台的约定以一定形式打包,发送给ClientIn模块。由ClientIn模块处理之后发送给Java后台。如果你们需要这部分的代码,发邮件给我。告诉我你们的姓名和班级。
转载于:https://www.cnblogs.com/coffeeliu/archive/2006/04/24/383913.html
2006毕业设计Delphi篇(二)相关推荐
- 三味书斋――Delphi篇
http://hubdog.csdn.net/UpdateList/ul20030102.htm 三味书斋――delphi篇 主持人:xingzhou(行舟),<程序员>杂志社技术编辑 嘉 ...
- 054_《奇思异想编程序Delphi篇》
<奇思异想编程序Delphi篇> Delphi 教程 系列书籍 (054) <奇思异想编程序Delphi篇> 网友(邦)整理 EMail: shuaihj@163.com 下载 ...
- 【SSRS】入门篇(二) -- 建立数据源
原文:[SSRS]入门篇(二) -- 建立数据源 通过 [SSRS]入门篇(一) -- 创建SSRS项目 这篇,我们建立了一个SSRS项目: 接下来,我们以 AdventureWorks2012 示例 ...
- 《高性能javascript》 领悟随笔之-------DOM编程篇(二)
<高性能javascript> 领悟随笔之-------DOM编程篇二 序:在javaSctipt中,ECMASCRIPT规定了它的语法,BOM实现了页面与浏览器的交互,而DOM则承载着整 ...
- mysql 基础篇(二) 账号、权限管理
mysql 基础篇(二) 账号.权限管理.备份与还原 建立账号密码: Grant all on test.* to "cj"@"localhost" ident ...
- 运动控制器编程_快速入门 | 篇二十一:运动控制器ZHMI组态编程简介一
点击上方"正运动小助手",随时关注新动态! 运动控制器ZHMI组态编程简介一 今天我们来学习一下,运动控制器的ZHMI组态编程简介.本文主要从产品概述.控制器连接触摸屏使用.HM ...
- 在java中重写方法应遵循规则的包括_Java面试题集合篇二
Java面试题之Java集合篇二1.遍历一个List有哪些不同的方式? List<String> strList = new ArrayList<>(); //使用for-ea ...
- 算法之数论应用篇(二)
算法之数论应用篇二 最大公约数 线性筛 Hankson的趣味题 欧拉函数 前言 可见的点(数学知识+欧拉函数) 最大公约数(可见的点扩展) 同余 取模的性质 定义 基本性质 运算规则 重要定理 重要定 ...
- 一台电脑怎么接两个显示器_电脑数码类目显示器 篇二:11.11抄作业,个人消费级显示器怎么选--20款好价显示器推荐_显示器...
2020-11-09 21:56:2572点赞390收藏91评论 想攒一台电竞主机.家用主机.酷炫主机无从下手?想省钱又怕性能不达标?值得买帮你打造定制化DIY装机工具,自助全网比价装机,提供最适合的 ...
最新文章
- oracle实例没有连到监听上6,oracle LISTENER未监听到oracle实例问题解决
- 清理服务器,不可不知的两个指令
- 汇编 debug调试
- 超图数据集管理基本操作 - 隐藏系统字段和添加字段索引
- Matlab 训练深度学习模型函数 trainingOptions
- 图的邻接表存储与深度优先遍历代码实现
- mysql每秒57000_MySQL 性能:使用 MySQL 5.7 实现每秒 50 万查询
- IIS问题:Server Application Error 的解决
- 期刊投稿状态_SCI投稿全过程解析及拒稿后处理对策
- 密码学专题 随机数文件
- AC日记——[USACO10MAR]仓配置Barn Allocation 洛谷 P1937
- python—IFrame:在jupyter notebook中展示某个网页的情况
- String常用函数
- 在IDEA中调试JavaScript代码
- 如何给pdf文件自动添加目录和书签?
- Intellij IDEA2017破解
- 网页(HTML)转换为PDF
- 动态规划练习一 18:买书
- Jetson TX2 apt换源
- Linux文件解hgc,【 大家一起来学习 Linux 源码 】:/*中英文注释*/
热门文章
- matlab虚拟现实之V-Realm Builder2使用NavigationInfo精确定位、建模
- mysql自动备份工具 linux_自动备份MYSQL方法 (Linux)
- java商品名称_Java统计商品信息
- 奇异值分解(SVD)详解
- pytroch model??(查看官方模型写法)
- jupyter生成数据集
- java 包装类型_2.Java基本类型与包装类型
- android actionbar tab,ActionBar+Fragment实现Tab
- 树莓派红外避障小车python_基于树莓派的环保“捡垃圾”机器人小车(避障、摄像、红外、WIFI)...
- mvc html安全检测,Spring MVC和HtmlUnit测试