以后的几篇我将介绍一下GPRSServer模块。
为什么叫GPRSServer?因为这个模块是和下层GPRS硬件模块通讯所用。
在这个模块中我们将和GPRS通讯的所有细节全部封装到wcomm_dll.dll动态连接库中。
这个动态链接库负责和下层具体通讯,包括UDP包的封装,下层通讯队列的维护和一些扩展功能等等。
具体代码:

unit Unit_dll;

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消息的:

 procedure ProcessMessage(var Msg:TMessage);message GPRSRECVMESS;

这个是消息的定义,再来看看这个消息处理函数具体做了什么工作:

procedure TFormGPRSServer.ProcessMessage(var Msg:TMessage);
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()这个函数的实现:

procedure TFormGPRSServer.ProcessData(dr:data_record);
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是如何实现的:

procedure TFormGPRSServer.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篇(二)相关推荐

  1. 三味书斋――Delphi篇

    http://hubdog.csdn.net/UpdateList/ul20030102.htm 三味书斋――delphi篇 主持人:xingzhou(行舟),<程序员>杂志社技术编辑 嘉 ...

  2. 054_《奇思异想编程序Delphi篇》

    <奇思异想编程序Delphi篇> Delphi 教程 系列书籍 (054) <奇思异想编程序Delphi篇> 网友(邦)整理 EMail: shuaihj@163.com 下载 ...

  3. 【SSRS】入门篇(二) -- 建立数据源

    原文:[SSRS]入门篇(二) -- 建立数据源 通过 [SSRS]入门篇(一) -- 创建SSRS项目 这篇,我们建立了一个SSRS项目: 接下来,我们以 AdventureWorks2012 示例 ...

  4. 《高性能javascript》 领悟随笔之-------DOM编程篇(二)

    <高性能javascript> 领悟随笔之-------DOM编程篇二 序:在javaSctipt中,ECMASCRIPT规定了它的语法,BOM实现了页面与浏览器的交互,而DOM则承载着整 ...

  5. mysql 基础篇(二) 账号、权限管理

    mysql 基础篇(二) 账号.权限管理.备份与还原 建立账号密码: Grant all on test.* to "cj"@"localhost" ident ...

  6. 运动控制器编程_快速入门 | 篇二十一:运动控制器ZHMI组态编程简介一

    点击上方"正运动小助手",随时关注新动态! 运动控制器ZHMI组态编程简介一  今天我们来学习一下,运动控制器的ZHMI组态编程简介.本文主要从产品概述.控制器连接触摸屏使用.HM ...

  7. 在java中重写方法应遵循规则的包括_Java面试题集合篇二

    Java面试题之Java集合篇二1.遍历一个List有哪些不同的方式? List<String> strList = new ArrayList<>(); //使用for-ea ...

  8. 算法之数论应用篇(二)

    算法之数论应用篇二 最大公约数 线性筛 Hankson的趣味题 欧拉函数 前言 可见的点(数学知识+欧拉函数) 最大公约数(可见的点扩展) 同余 取模的性质 定义 基本性质 运算规则 重要定理 重要定 ...

  9. 一台电脑怎么接两个显示器_电脑数码类目显示器 篇二:11.11抄作业,个人消费级显示器怎么选--20款好价显示器推荐_显示器...

    2020-11-09 21:56:2572点赞390收藏91评论 想攒一台电竞主机.家用主机.酷炫主机无从下手?想省钱又怕性能不达标?值得买帮你打造定制化DIY装机工具,自助全网比价装机,提供最适合的 ...

最新文章

  1. oracle实例没有连到监听上6,oracle LISTENER未监听到oracle实例问题解决
  2. 清理服务器,不可不知的两个指令
  3. 汇编 debug调试
  4. 超图数据集管理基本操作 - 隐藏系统字段和添加字段索引
  5. Matlab 训练深度学习模型函数 trainingOptions
  6. 图的邻接表存储与深度优先遍历代码实现
  7. mysql每秒57000_MySQL 性能:使用 MySQL 5.7 实现每秒 50 万查询
  8. IIS问题:Server Application Error 的解决
  9. 期刊投稿状态_SCI投稿全过程解析及拒稿后处理对策
  10. 密码学专题 随机数文件
  11. AC日记——[USACO10MAR]仓配置Barn Allocation 洛谷 P1937
  12. python—IFrame:在jupyter notebook中展示某个网页的情况
  13. String常用函数
  14. 在IDEA中调试JavaScript代码
  15. 如何给pdf文件自动添加目录和书签?
  16. Intellij IDEA2017破解
  17. 网页(HTML)转换为PDF
  18. 动态规划练习一 18:买书
  19. Jetson TX2 apt换源
  20. Linux文件解hgc,【 大家一起来学习 Linux 源码 】:/*中英文注释*/

热门文章

  1. matlab虚拟现实之V-Realm Builder2使用NavigationInfo精确定位、建模
  2. mysql自动备份工具 linux_自动备份MYSQL方法 (Linux)
  3. java商品名称_Java统计商品信息
  4. 奇异值分解(SVD)详解
  5. pytroch model??(查看官方模型写法)
  6. jupyter生成数据集
  7. java 包装类型_2.Java基本类型与包装类型
  8. android actionbar tab,ActionBar+Fragment实现Tab
  9. 树莓派红外避障小车python_基于树莓派的环保“捡垃圾”机器人小车(避障、摄像、红外、WIFI)...
  10. mvc html安全检测,Spring MVC和HtmlUnit测试