电话、手机通信开发的TAPI笔记

来源:互联网 发布:mac辣椒红试色 编辑:程序博客网 时间:2024/06/11 16:42

一.前言

 

数据通讯的重要性是不言而喻的,特别是在写程序的过程中掌握数据通讯技术,了解各种通讯的方法及其优缺点是很重要的。调制解调器是目前进行远程通讯的一种重要工具,基于调制解调器的应用越来越多,TAPI就是Microsoft及Intel公司联合开发的,基于MODEM,电话线进行数据传输的一种应用程序接口,TAPI既适用于BC++也适用于VC++。

 

近一段时间我一直使用TAPI实现两台机器间用MODEM,电话线之间进行数据传输,现总结如下:

 

 

 

   Windows95/98基于API的通信手段大致分为以下几种:

 

1. 基于TCP/IP协议的WinSock API,可实现局域网上或互联网上的微机通信;

 

2. 基于进程之间的通信技术:动态数据交换(DDE);

 

3. 基于直接电缆连接的通信技术,可直接操作串行口、交行口以及远红外线接口;

 

4. 基于电话线路的通信应用程序接口(TAPI),可方便地控制调制解调器。

 

 

 

二.通讯过程

 

   TAPI的基本通讯过程包括如下几步:

 

步骤

说明

 

初始化TAPI环境

使用lineInitialize函数初始化TAPI32.DLL,获得TAPI句柄。此时必须指定一个回调函数,由此回调函数处理消息。

 

应答方初始化

1.   通过lineNegotiateAPIVersion确定使用TAPI的版本;

 

2.   用lineOpen打开线路,得到HLINE句柄,dwPrivileges函数必须使用LINECALLPRIVILEGE_MONITOR+LINECALLPRIVILEGE_OWNER,与呼叫方不同;

 

呼叫方进行呼叫

1.   通过lineNegotiateAPIVersion确定使用TAPI的版本;

 

2.   用lineOpen打开线路,得到HLINE句柄,dwPrivileges函数必须使用LINECALLPRIVILEGE_NONE;

 

3.   创建拨号参数,类型为:LPLINECALLPARAMS;

 

4.   用lineMakeCall或lineDial进行拨号,两者的区别是,使用前者是还没有HCALL句柄的情况下,使用此拨号可得到HCALL句柄,而lineDial是在HCALL句柄已得到的情况下使用。

 

回调函数的处理

回调函数对消息进行处理,最主要的消息包括:

 

1.   LINECALLSTATE_OFFERING:此函数由应答方捕获,得到此消息表明已接收到拨号方的呼叫,应进行回应,回应的格式为:lineAnswer( (HCALL)dwDevice,NULL,0 );

 

2.   LINECALLSTATE_BUSY, LINECALLSTATE_IDLE, LINECALLSTATE_SPECIALINFO:在拨号或应答过程中出现错误,应断接;

 

3.   LINECALLSTATE_DISCONNECTED:某一方断接,此时可以判断到底是哪一种原因造成断接,同时也应调用断接函数;

 

4.   LINECALLSTATE_CONNECTED:已连接上并建立线路,此时应调用lineGetID函数得到MODEM的句柄,必要时应清空MODEM缓冲区,以便开始进行数据的传输。

 

断接

1.   任何一方可以调用linDrop(HCALL)来停止呼叫,该函数将会发送LINECALLSTATE_IDLE消息给回调函数

 

2.   当任何一方收到LINECALLSTATE_IDLE消息时应调用lineDeallocateCall(hCall)来释放掉占用的呼叫资源;

 

3.   当收到LINECALLSTATE_DISCONNECTED 消息时应使用lineClose(HLINE)释放由lineOpen 分配的资源,调用lineShutDown(HLINEAPP)释放为线路设备分配的资源

 

数据的发送与接收

使用ReadFile与WriteFile函数发送与接收数据,共中的文件句柄好是MODEM句柄。

 

 

 

 

 

 

 

 

三.数据发送与传输

 

ReadFile与WriteFile并非TAPI的函数集成员函数,TAPI并不提供数据传输的函数。

 

(一)函数调用格式:

 

ReadFile的调用格式为:

 

ReadFile(文件句柄,发送的数据的缓冲区地址,欲发送多少字节数据,实际发送了多少字节数据,一个指向OVERLAPPED结构的指针);

 

1. 文件句柄:此处即为MODEM句柄;

 

2. 发送数据的缓冲区地址:可为char *或LPDWORD格式,传送的数据为二进制格式;

 

3. 欲发送多少字节数据:用户指定,但也可以使用ClearCommError函数来测到当前MODEM缓冲区有多少字节数据,然后有多少读多少。

 

4. 实际发送了多少字节数据:返回值;

 

5. OVERLAPPED结构的指针:

 

 

 

(二)传输模式

 

在95/98下:ReadFile与WriteFile有两种模式,一种是等待模式,一种是非等待模式。

 

等待模式的格式为:

 

DWORD len;

 

ReadFile(g_hCommFile,lpBuffer,256,&len,NULL);

 

此时必须完成了读写操作函数才会返回,实际读写的字节数在len中,最后一个参数必须为NULL。

 

非等待模式的格式为:

 

OVERLAPPED myOVLP = {0, 0, 0, 0, NULL};

 

myOVLP.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

 

ReadFile(g_hCommFile,lpBuffer,256,NULL,&myOVLP);

 

GetOverlappedResult(g_hCommFile,&myOVLP,&len,TRUE)

 

CloseHandle(myOVLP.hEvent);

 

此时ReadFile函数会马上返回,第四个参数会被忽略,实际读写的字节数由GetOverlappedResult函数返回,如果读写成功,此函数为返回非0值,最后一个函数为TRUE,表示等待方式,为FALSE表示非等待。

 

 

 

在NT下必须使用OVERLAPPED参数,调用格式与95/98下的非等待方式类似。

 

 

 

(三)如何保证数据传输的正确性

 

在等待模式下,如果读写操作不完成,函数就会一直处于挂起状态;

 

在非等待模式下,函数调用后会马上返回,此时应调用GetOverlappedResult函数来判断,如果此函数返回FALSE,就应进一步判断,例如:

 

WriteFile(g_hCommFile,lpBuffer,256,NULL,&myOVLP);

 

while(!GetOverlappedResult(g_hCommFile,&myOVLP,&len,TRUE))

 

{

 

dwError=GetLastError();

 

if(dwError == ERROR_IO_INCOMPLETE)

 

    continue;

 

else

 

    出错;

 

}

 

   

 

(四)如何提高传输性能

 

因为MODEM的缓冲区毕竟非常有限,如果某一方出现阻塞,另一方就不得不陷入等待之中,而且双方之间的协调会使速率非常之低,此时可以采用缓冲区的办法,发送与接收双方都开辟一个缓冲区(应是循环的),数据直接写入缓冲区中,然后用线程的方法,发送方不断的判断缓冲区中是否有数据,如果有发送方就发送到MODEM中,接收方则不断判断MODEM中是否有数据,如果有就读入缓冲区中。

 

 

 

就MODEM传输速度,我使用的环境是内线,没有通过交换机,满载的情况下每秒在6K字节/秒左右。

 

 

 

四.消息的处理

 

TAPI由回调函数进行消息处理,回调函数在初始化TAPI时创建,消息的处理在TAPI的使用过程中是至关重要的。以下是一些主要的消息:

 

1.    LINECALLSTATE_IDLE

没有呼叫,为空,此时应断接,释放掉占用的资源;

 

2.    LINECALLSTATE_BUSY

线路忙或设备忙,此时应断接,释放掉占用的资源;

 

3.    LINECALLSTATE_SPECIALINFO

特别的消息,此时应断接,释放掉占用的资源;

 

4.    LINECALLSTATE_OFFERING

应答方已收到呼叫方信号,此时应进行应答,调用lineAnswer函数;

 

5.    LINECALLSTATE_CONNECTED

已连接成功,此时可进行数据的传输,但必须先得到MODEM的句柄;

 

6.    LINECALLSTATE_DISCONNECTED

已断接,此时应释放掉占用的资源。

 

注意:这篇文章来源于网络,我用于学习,收藏于此,如有侵权请通知我,我将删除之。