`
yexin218
  • 浏览: 970720 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

驱动和应用层的异步通信

阅读更多

作 者: sislcb
时 间: 2008-01-28,11:13:28
链 接: http://bbs.pediy.com/showthread.php?t=59015

这里来简单的讲解下驱动和应用层的异步通信,上次我写了驱动和应用层的三种基本通信方法,但是那三种方法都是通过同步的方法来实现的,就是说,在应用层向驱动层发送消息后,就堵死在那里等待驱动层的返回了,而异步的概念就是,应用层向驱动发送消息后,就马上返回了,而在驱动层的消息触发后,再将该消息反馈给应用层。

给个网上的例子:
同步就是你叫我去吃饭,我听到了就和你去吃饭;如果没有听到,你就不停的叫,直到我告诉你听到了,才一起去吃饭。
异步就是你叫我,然后自己去吃饭,我得到消息后可能立即走,也可能等到下班才去吃饭。

其实在明白了三种通信方式后,很容易使用异步方式来通信。

在调用DeviceIoControl时,不指定FILE_FLAG_OVERLAPPED标志,表示以同步方式调用,调用线程将被阻塞直到控制操作完成.
当指定FILE_FLAG_OVERLAPPED标志调用DeviceIoControl,表示以异步方式调用,调用线程不立即阻塞,直到调用线程需要结果时,调用者调用事件等待函数,等待驱动发出事件.
在异步调用时,得使用事件(event)来通信.

下面看应用层的代码:

// 初始化时创建设备
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  //创建设备
  try
    m_hCommDevice := CreateFile('\\.\Overlapp',  GENERIC_READ or GENERIC_WRITE,  FILE_SHARE_READ, nil,
                      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0);
    //执行异步I/O的设备必须用FILE_FLAG_OVERLAPPED标志打开

    hEvent := CreateEvent( nil, False, False, nil);     //创建自动重置的事件
  except
    MessageBox(Handle, '创建设备失败', '驱动应用层通信', MB_OK + MB_ICONWARNING);
  end;
end;

//异步通信按钮,创建线程和驱动通信
procedure TfrmMain.btnBufferdClick(Sender: TObject);
var
  hThread:THandle;
  dwThreadID:DWORD;
begin
  hThread  := CreateThread(nil, 0, @WaitForNotify, self, 0, dwThreadID);
  CloseHandle(hThread);
end;

//线程的处理代码
//初始化一个OVERLAPPED 结构,然后用DeviceIoControl来通信
//在WaitForSingleObject等待返回
procedure WaitForNotify;
var
  dwReturn: DWORD;
  inData:array[0..1023] of char;
  outData:array[0..1023] of char;
  ol:OVERLAPPED ;
begin
  StrPCopy(inData, Trim(frmMain.edtBufferd_in.Text));

  //OVERLAPPED结构的Offset,OffsetHigh和hEvent成员必须被初始化。在这里初始化为0
  FillMemory(@ol, sizeof(OVERLAPPED), 0);
  ol.hEvent := frmMain.hEvent;

  if frmMain.m_hCommDevice <> 0 then
    DeviceIoControl(frmMain.m_hCommDevice, IOCTL_OVERLAP_BUFFERED_IO, @inData,  Length(inData), @outData, Length(outData), dwReturn, @ol);


  //调用WaitForSingleObject并传递设备内核对象的句柄。WaitForSingleObject会挂起调用线程直至内核对象变成有信号态。
  //设备驱动在它完成I/O后使内核对象有信号。在WaitForSingleObject返回后,I/O被完成 .
  while WaitForSingleObject(frmMain.hEvent,  100) = WAIT_TIMEOUT do
  begin
  end;

  GetOverlappedResult(frmMain.m_hCommDevice, ol, dwReturn, TRUE);
  frmMain.edtBufferd_out.Text := outData;
end;

//这里触发驱动将数据传输回来,异步消息得以完成
procedure TfrmMain.btnNotifyClick(Sender: TObject);
var
  dwReturn:DWORD;
begin
  if m_hCommDevice <> 0 then
    DeviceIoControl(m_hCommDevice, IOCL_OVERLAP_NOTIFY, nil, 0, nil, 0, dwReturn, nil);
end;

//退出时,关闭句柄,这时候如果irp还未处理,即btnNotifyClick这个函数没有触发
//则驱动中会触发取消irp的请求。
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if(m_hCommDevice <> 0) then
    CloseHandle(m_hCommDevice);
  if (hEvent <> 0) then
    CloseHandle(hEvent);
end;

 驱动层代码

//接受到消息的处理函数
NTSTATUS Overlap_IoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS status = STATUS_NOT_SUPPORTED;
    PIO_STACK_LOCATION irpStack = NULL;
    UINT sizeofWrite = 0;

    DbgPrint("Overlap_IoControl\r\n");

    irpStack = IoGetCurrentIrpStackLocation(Irp);    

    if(irpStack)
    {
        switch(irpStack->Parameters.DeviceIoControl.IoControlCode)
        {
            case IOCTL_OVERLAP_BUFFERED_IO:   //异步通信消息
         status = Irp->IoStatus.Status = STATUS_PENDING; 
         Irp->IoStatus.Information = 0;
         IoMarkIrpPending(Irp); 
         gUserMessageIrp = Irp;//保存请求的irp
         IoSetCancelRoutine(Irp, DriverCancelIrp); //设置irp取消例程,在应用程序退出时,触发
         return status; 
      case IOCL_OVERLAP_NOTIFY:                                //获取数据事件 
         COMM_BufferedIo(gUserMessageIrp, irpStack);         //处理原来的irp,将传进来的数据传输出去
                 return status;
      default:
        return status;
        }
    }

  return status;
}

//当通知要获取数据时,获得异步的irp,然后传输数据
NTSTATUS COMM_BufferedIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PVOID pInputBuffer, pOutputBuffer;
  ULONG  outputLength, inputLength;

    DbgPrint("COMM_BufferedIo\r\n");

  outputLength = pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;
    inputLength  = pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;
    pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;   //输出缓冲区
    pInputBuffer = Irp->AssociatedIrp.SystemBuffer;    //输入缓冲区

    if(pInputBuffer && pOutputBuffer)
    {              
    DbgPrint("COMM_BufferedIo UserModeMessage = '%s'", pInputBuffer);
        RtlCopyMemory(pOutputBuffer, pInputBuffer, outputLength);
    Irp->IoStatus.Status = STATUS_SUCCESS; 
    Irp->IoStatus.Information = sizeof(pOutputBuffer); 
    IoCompleteRequest(Irp,IO_NO_INCREMENT); //设置该irp已经完成
        status = STATUS_SUCCESS;
    }
    return status;
}

//取消irp的例程
VOID DriverCancelIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) 
{ 
  //UNREFERENCED_PARAMETER这个宏用于去掉一个函数的参数未用或函数中定义了一个局部变量却从未用过的编译警告
    UNREFERENCED_PARAMETER(DeviceObject);

    KdPrint(("UserMessageCancelIrp....\n"));
    
    if ( Irp == gUserMessageIrp)
        gUserMessageIrp = NULL; 

    Irp->IoStatus.Status = STATUS_CANCELLED; 
    Irp->IoStatus.Information = 0; 
    IoCompleteRequest(Irp,IO_NO_INCREMENT); 
} 

 流程如下:
1、
应用层:
   通知异步消息
   等待返回
驱动层:
   收到消息
   设置irp取消例程
   保存该irp

2、
应用层:
   通知获取数据,即完成异步消息
驱动层:
   拷贝数据到输出缓冲区,完成该irp

在这里我是通过手动的方式来触发异步消息的完成,而不是由系统的消息触发的。主要是为了演示的方便

分享到:
评论

相关推荐

    驱动和应用层的三种通信方式

    其次,消息队列是一种异步通信机制,它允许驱动程序和应用层之间传递结构化的数据包。应用层将消息放入队列,驱动程序则在需要时从队列中取出并处理。这种方式特别适合于那些不需立即响应或者处理时间不确定的通信...

    运用事件应用程序和驱动通讯同步

    在IT领域,尤其是在系统开发和硬件交互中,事件应用程序和驱动通信同步是至关重要的技术环节。事件是操作系统中用于进程间通信(IPC)的一种机制,它允许一个或多个线程等待特定条件的发生,如文件完成写入、网络...

    基于事件驱动和异步通信体系结构的Web服务器设计

    本文介绍了基于事件驱动和异步通信体系结构的Web服务器设计思想,并详细讨论了其关键技术——适配子层aSocket的设计与实现。通过实验证明,这种设计能够显著提高服务器的并发处理能力和性能。未来的研究方向可以...

    c++做的异步通信,使用socket的典型例子

    异步通信通常涉及事件驱动编程,其中最常用的是回调函数和I/O复用技术,如多路复用I/O(select、poll、epoll等)。当一个socket上的事件发生时,如数据到达或连接请求,操作系统会通知应用程序,而不是让程序阻塞...

    TCP/UDP/IP/IPv6 异步通信调试工具

    异步通信通常基于事件驱动或回调机制。当网络事件发生时,比如数据到达,系统会通知应用程序,而不是让应用程序一直等待。这种方式使得程序能够在多任务间快速切换,提高了整体性能,特别适合于高并发场景,如服务器...

    基于TCP的异步通信例子

    2. **事件驱动编程**:异步通信通常与事件驱动编程模型相结合。在这种模型中,程序会注册对特定事件(如数据到达或连接建立)的监听,当这些事件发生时,程序通过回调函数来响应。 3. **IOCP(I/O完成端口)**:在...

    C# Socket 网口 异步通信

    综上所述,C#的Socket异步通信不仅涉及到基础的网络编程概念,还包括了高级的异步编程技术,如事件驱动、委托和async/await。通过理解和熟练掌握这些知识点,开发者能够构建出高效、健壮的网络应用程序。FastSocket...

    tcp与udp同步、异步通信

    学习这个程序集,不仅可以了解TCP和UDP的基础知识,还能深入理解MFC在网络编程中的应用,掌握同步与异步通信的区别和实现方式。这对于提升网络编程技能,尤其是开发涉及网络通信的应用程序,是非常有价值的。

    linux c uart 串口通信 应用层代码

    总结,Linux下的UART串口通信涉及硬件驱动、应用层接口和C语言编程。理解和掌握这些知识点,对于开发需要串口通信的项目至关重要。通过实际编写和调试应用层代码,你可以深入理解UART通信的工作原理及其在Linux环境...

    精选_Minifilter驱动程序与用户层程序通信_源码打包

    这种方式提供了可靠的异步通信,适用于大量数据交换。 4. **文件系统流**:通过在特定文件中写入数据,Minifilter驱动程序可以在读取文件时获取信息。这种方式需要确保数据格式的一致性和安全性。 5. **设备驱动...

    基于STM32的事件驱动框架的应用

    在实验中,QP框架的QF部分充当软件总线,通过事件分发机制处理来自按键的事件,实现了活动对象的异步通信。这种设计使得事件可以在系统中松散耦合的组件间高效传播,增强了系统的灵活性。 综上所述,基于STM32的...

    socket通信示例代码(线程、异步)

    在TCP/IP模型中,Socket位于传输层和应用层之间,它为应用程序提供了一种标准的方式来创建网络连接。 服务器端的Socket编程通常包括以下步骤: 1. 创建Socket:通过调用`socket()`函数创建一个Socket对象。 2. 绑定...

    基于java的进程间异步通信系统的设计与实现

    本篇文章将深入探讨基于Java的进程间异步通信系统的设计与实现,特别关注其在Android环境中的应用。 首先,我们需要理解什么是进程间通信。进程是操作系统分配资源的基本单位,而进程间的通信则是不同进程之间交换...

    单片机的同步-异步通信,包括发送部分程序、接收部分程序、主控制程序,针对不同单片机.zip

    同步通信和异步通信是单片机通信的两种主要类型,它们各有特点和适用场景。 1. **同步通信**: 同步通信是一种严格的时序通信方式,两个通信节点必须遵循相同的时钟信号进行数据交换。这意味着发送端和接收端都必须...

    NDIS中间层 NDIS6过滤驱动开发笔记

    同时,过滤驱动中也需要掌握如何分配和管理NetBufferListPool,以及如何通过DeviceIoControl进行驱动程序与应用层的异步通信。 在遇到驱动程序中的bug和错误时,例如DRIVER_CORRUPTED_EXPOOL错误,需要有能力对内核...

    mina异步通信

    Mina的核心特性是其异步通信模型,它允许应用程序在不阻塞线程的情况下处理大量并发连接,从而提高了系统的吞吐量和响应速度。 1. **异步通信**:在Mina中,I/O操作是非阻塞的,这意味着当一个I/O请求被发起时,...

    电信设备-一种基于驱动层处理串口通信的方法.zip

    3. **驱动层与应用层交互**:在基于驱动层的串口通信中,应用层通过系统调用或者API与驱动层交互。例如,应用可以调用`write()`函数发送数据,`read()`函数接收数据,而驱动层则负责实际的数据传输操作。 4. **电信...

    NDIS 协议层中间层驱动程序

    NDIS(Network Driver Interface Specification)协议层中间层驱动程序是网络驱动程序模型中的一个重要组成部分,它位于网络适配器驱动程序(称为NDIS微型端口驱动程序)和上层协议驱动程序之间,如TCP/IP协议栈。...

    使用CAsyncSocket类实现异步网络通信

    - **示例**:在客户端,可以通过在不同的线程中处理连接、接收和发送数据等操作来实现高效的异步通信。 ##### 5. 实现细节 - **客户端示例**: - 创建一个新类`ClientSocket`继承自CAsyncSocket。 - 在类中声明...

    Android上层与驱动交互完整篇(APK->JNI->HAL->DRV)

    总结来说,Android上层应用与驱动的交互是一个涉及Apk、JNI、HAL和DRV的多层通信过程。Apk通过JNI调用HAL接口,HAL封装硬件操作并调用相应的驱动,驱动则直接控制硬件设备。这种层次化的架构使得Android系统能够灵活...

Global site tag (gtag.js) - Google Analytics