在Windows环境中怎样截获TCP/IP数据包???有没有详细点的原理说明或是资料?

CDSoftwareWj 2001-09-13 05:04:52
有知道的吗???帮帮忙啦……
...全文
402 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
dragon_lh 2001-09-17
  • 打赏
  • 举报
回复
好资料!
CDSoftwareWj 2001-09-17
  • 打赏
  • 举报
回复
好资料!!!!为了叫大家都看看晚点给分可以吗??hehe^^
cctime 2001-09-14
  • 打赏
  • 举报
回复
无需驱动程序的Sniffer-IPMon

在Windows平台上实现的Sniffer一般都需要自己写驱动程序,例如在Win9x
下面是通过写一个驱动程序用Hook_Device_Service( )来挂接ndis.vxd提供
的服务,在WinNT/2K下面则一般是需要写一个中间驱动程序(请参考白云黄
鹤站的相关文章以及http://www.pcausa.com的论述)。
Arkady Frankel(arkadyf@hotmail.com) 在CodeGuru上给出了一个无需自
己编写驱动程序的Sniffer-IPMon。该程序利用了WinSock 2的特性,只能
运行在Win2K平台上。WinSock 2允许程序使用WSAIoctl( )给一个SOCK_RAW类
型的socket设置SIO_RCVALL属性,这样该socket就可以收到所有经过本机的
数据。 下面简单分析一下其实现方法。

首先打开一个socket,参数必须是 AF_INET、SOCK_RAW和IPPROTO_IP,否则
不能设置SIO_RCVALL属性:

m_s = socket( AF_INET , SOCK_RAW , IPPROTO_IP ) ;
if( INVALID_SOCKET == m_s )
{
dwErr = WSAGetLastError() ;
sprintf( szErr , "Error socket() = %ld " , dwErr ) ;
AfxMessageBox( szErr ) ;
return ;
}

然后可以设置一下该socket的超时参数等选项:

int rcvtimeo = 5000 ;
if( setsockopt( m_s , SOL_SOCKET , SO_RCVTIMEO ,
(const char *)&rcvtimeo , sizeof(rcvtimeo) ) == SOCKET_ERROR)
{
dwErr = WSAGetLastError() ;
sprintf( szErr , "Error WSAIoctl = %ld " , dwErr ) ;
AfxMessageBox( szErr ) ;
closesocket( m_s ) ;
return ;
}

再将该socket与本机的某个网络接口绑定(注意绑定的IP地址不能是INADDR_ANY):

sa.sin_family = AF_INET;
sa.sin_port = htons(7000);
sa.sin_addr.s_addr= m_iphostsource;
if (bind(m_s,(PSOCKADDR)&sa, sizeof(sa)) == SOCKET_ERROR)
{
dwErr = WSAGetLastError() ;
sprintf( szErr , "Error bind() = %ld " , dwErr ) ;
AfxMessageBox( szErr ) ;
closesocket( m_s ) ;
return ;
}

接下来就可以设置SIO_RCVALL属性。此后就可以利用这个socket来读取经
过本机的数据包了。IPMon创建了一个新线程专门来读取该socket,以防止
处理用户输入的主线程被阻塞。

if( SOCKET_ERROR != WSAIoctl( m_s, SIO_RCVALL , &dwBufferInLen,
sizeof(dwBufferInLen),&dwBufferLen, sizeof(dwBufferLen),
&dwBytesReturned , NULL , NULL ) )
AfxBeginThread( threadFunc , (LPVOID)this );
else
{
dwErr = WSAGetLastError() ;
sprintf( szErr , "Error WSAIoctl = %ld " , dwErr ) ;
AfxMessageBox( szErr ) ;
closesocket( m_s ) ;
return ;
}

新线程中读取socket的代码也非常简单,只需要反复调用recv( )即可:

memset( buf , 0 , sizeof(buf) ) ;
iRet = recv( pDlg->m_s , buf , sizeof( buf ) , 0 ) ;
if( iRet == SOCKET_ERROR )
{
dwErr = WSAGetLastError() ;
sprintf( szErr , "Error recv() = %ld " , dwErr ) ;
continue ;
}
else
if( *buf )
{
bufwork = buf ;
pIpHeader = (IPHEADER *)bufwork ;
WORD iLen = ntohs(pIpHeader->total_len) ;
......
}

此时pIpHeader就指向buf中的RAW IP数据包,如何处理就看自己的需要了。

总之这个实现是非常方便的,不用自己编写复杂的抓包代码,所有重要
的工作都由WinSock自己封装了。WSAIoctl( )还有其它一些比较有用的
参数,如SIO_RCVALL_MCAST参数使socket可以接收所有的多播数据,
SIO_RCVALL_IGMPMCAST参数则可以接收IGMP多播数据。实际测试的时候
发现IPMon经常无法看到本机发出去的数据包(偶尔能收到),不知是什
么原因。
explorer007 2001-09-13
  • 打赏
  • 举报
回复
转贴...

这个文档是VPACKET的说明.VPACKET是Windows 95下的一个虚拟设备驱动
程序,它可以通过WIN32程序对安装在PC机上的任何网卡进行直接读写操作.
直接网卡读写对编写网络管理程序和那些想实现自己的意图的编程者是十分有
用的.这个驱动程序是P32编程环境[1]的一部分.P32是一个堪培拉大学用于操
作系统和协议设计课程的WIN32程序包.

1.介绍
WIN32程序平台不支持低层次的直接的网卡操作.需要这种操作的程序(由于
种种原因)必须用一个自定制的虚拟设备驱动程序(VXD).VXD提供一个在底层网
络控制接口(NICS)和高层的WIN32程序间的一个服务接口.它的基本结构见图一.

_________________
| 应用程序 |
|_________________|
/| |
-----------|--------------------------------------------
|
_____\|/___________
| VPACKET |
| VXD |
|_________________|
/|
/| |
_____\|/___________________________________________
| |
| NDIS 3.10 |
|___________________________________________________|
/|\ /|\ /| | | |
___\|/___ ___\|/___ ___\|/___
| NIC 0 | | NIC 0 | ............... | NIC N |
|_______| |_______| |_______|
图一: 结构
一个程序必须首先用一个WIN32_API函数:CreateFile将此VXD装入内存,然
后才能调用WIN32设备I/O控制函数来实现此VXD提供的功能.
2.关于接口抽象层
正像在图一中所看到的那样,这个虚拟设备驱动程序并没有直接面对已安装
好的底层网络控制接口.在网络硬件和VXD之间有一个叫做NDIS 3.10的接口抽象
层.使用这种接口抽象层的意图在于保护需要NIC接口的软件不受底层网络适配
器特殊硬件细节的影响.因此这个VAPCKET VXD可以方便的同安装在不同机器上
的任何NIC接口进行通讯,但这台机器上的网卡必须是支持NDIS的.
注意,不同版本的NDIS对网卡的支持有些不同.尤其是微软的Dialup网卡(
PPPMAC)不支持NDIS.因为一个普通的NDIS Send函数在这种网卡上传送不了任何
数据.此外,这种网卡也不支持NDSI所支持的网卡所具有的数字统计硬件.
3.怎样装入一个VXD
一个WIN32程序使用一个特定的形式调用WIN32_API函数:CreateFile来装入
VXD.下面的代码演示了如何装入VAPCKET VXD.

#include <windows.h>
HANDLE hVxD;
hVxD = CreateFile("\\\\.\\VPACKET.VXD",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED |
FILE_FLAG_DELETE_ON_CLOSE,
NULL);

NULL);
if (hVxD == INVALID_HANDLE_VALUE)
return SYSERR;
第一个参数说明将要装入的VPACKET.VXD所在的目录.第六个参数应特别注
意:它指明此驱动程序支持异步操作(FILE_FLAG_OVERLAPPED),同时也指出当VXD
关闭时应当从内存中被释放(FILE_FLAG_DELETE_ON_CLOSE).
此函数要求异步操作立即返回到它的调用者那里,而不必非要等到操作被完
成.应用程序必须用另外的方法(下面将要提到)来断定操作是否已经完成.
调用CreateFile函数所返回的句柄不是一个普通的文件句柄.实际上,程序
就是通过它来完成设备驱动程序所提供的功能.
VPACKET VxD能被"打开"无数次,每次调用CreateFile函数将返回一个与其
它各次不同的句柄.仅仅在第一次调用CreateFile函数时是真正的装入和执行此
VxD,其它时刻调用CreateFile函数仅仅是返回一个新句柄而已.
VPACKET VxD的一个显著特征就是不需要安装或者设置,因此没有相应的inf
文件.所有的设置工作在这个VxD被执行并被确定的绑定到一个或多个网络接口
时被自动完成.
4.怎样从内存中卸载VxD
这个VxD能够被WIN32_API函数CloseHandle所卸载,释放从CreateFile函数
所获得的句柄.假如此驱动程序被打开多次,则必须当所有的句柄都被释放时此
VxD才被卸载.
5.怎样绑定到网络接口层
当VPACKET VxD被装入和执行时,它必须与一个特定的网络接口控制器发生
联系,即绑定.绑定可以通过下面的Bind函数来完成.
int Bind(HANDLE hVxD, BYTE* inBuffer)
{
HANDLE hEvent;
DWORD cbRet;
OVERLAPPED ovlp = {0,0,0,0,0};
int result;
int cbIn = 5;
hEvent = CreateEvent(0, TRUE, 0, NULL);
if (!hEvent)
return SYSERR;
ovlp.hEvent = hEvent;
result = DeviceIoControl(hVxD,
IOCTL_PROTOCOL_BIND,

IOCTL_PROTOCOL_BIND,
inBuffer,
cbIn,
inBuffer,
cbIn,
&cbRet,
&ovlp);
if (!result)
GetOverlappedResult(hVxD, &ovlp, &cbRet, TRUE);
CloseHandle(hEvent);
return OK;
}
第一个参数是先前调用的CreateFile函数所返回的句柄.第二个参数是命名句柄
所将要绑定的适配器的字符串.这个字符串可以从Windows95的注册表的如下目录
找到:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\Net
注意:对于每一个CreateFile函数所返回的句柄,应用程序再进行任何其他
操作之前必须被绑定.
6.设备驱动API函数
一个WIN32程序可以用DeviceIoControl函数来调用设备驱动程序所提供的服
务功能.上面所列出的Bind函数,第一个参数是CreateFile函数所返回的句柄,第
二个参数是下列函数代码之一:
IOCTL_PROTOCOL_QUERY_OID 得到详细的目标Object的ID
IOCTL_PROTOCOL_SET_OID 设置详细的目标ObjectID
IOCTL_PROTOCOL_STATISTICS 得到特定网卡(适配器)的状态
IOCTL_PROTOCOL_RESET 复位网卡(适配器)
IOCTL_PROTOCOL_READ 从网络上接受一个包
IOCTL_PROTOCOL_WRITE 在网上发送一个包
IOCTL_PROTOCOL_MACNAME 得到网卡驱动的名称
IOCTL_PROTOCOL_BIND 绑定VPACKET VXD到特定网卡(适配器)
使用以上操作的例子在附录中给出.
7.异步操作
Bind函数说明了异步操作是怎样在WIN32程序中实现的.
WIN32_API函数CreateEvent被调用后的返回值存入OVERLAPPED结构的成员hEvent
句柄.OVERLAPPED结构中剩下的成员被赋值为0.在调用DevIoControl函数时
OVERLAPPED结构体的地址指针被作为最后一个参数传递给设备驱动程序.然后驱
动程序便开始进行操作并返回一个值.当驱动程序完成所要求的操作时将发给一

动程序便开始进行操作并返回一个值.当驱动程序完成所要求的操作时将发给一
个特定的事件一个信号.与此同时WIN32程序可以完成一些其他事情.在绑定结束
之前,Bind函数干不了更多的事情.因此在Bind的线程中仅仅调用了WIN32_API函
数GetOverlappedResult.这个函数会阻止程序运行,直到特定事件收到操作完成
的信号.(因为此函数最后一个参数恒为真实值TRUE).
参数3: 包含指定操作所需要的输入数据的缓冲区的地址
参数4: 上面提到的缓冲区大小
参数5: 保留指定操作的返回信息的缓冲区的地址
参数6: 上面提到的缓冲区大小
参数7: 一个双字(DWORD)变量的地址.这个变量表示驱动程序所返回的字节
数.注意:这个变量也被用作GetOverlappedResult函数的参数.
当应用程序需要读出网卡所接受到的数据时,异步输入输出机制的强大优势将会
更明显.应用程序(往往如此)不可能预先知道何时数据包将会从网上到达.因此
程序可以完成一些其他的处理(如:处理Windows 95的消息)和通过调用
GetOverlappedResult函数来检查是否有数据包到达.假如GetOverlappedResult
函数返回值为FALSE,同时调用GetLastError函数返回ERROR_IO_PENDING,应用程
序就可以知道没有数据包到达.假如GetOverlappedResult函数返回值为TRUE,则
应用程序便知道有数据包到达,因此可以进行一些操作.
9.结论
这个VPACKET虚拟设备驱动程序提供给运行于Windows 95下的WIN32应用程序
一种简单且有效的直接进行网络接口控制的机制.
在P32编程环境中,利用这个驱动程序,在Comer和Stevens[2]编写的代码基础
之上实现了完全的TCP/IP协议.这个程序支持复合网络接口,完全的IP协议和入口
功能.
作者的版本中还有一些附加特征:支持IP地址和端口列表.一个局域网中的主
机可以使用另一个局域网中的一个可用的IP地址.所有局域网中的主机可以使用
端对端(PPP)协议的IP地址连接到互联网(Internet)服务商.
10.参考及附注
[1] 有关信息可在以下网址获得:
http://willow.canberra.edu.au/~chrisc/p32.html
[2] 有关信息在<<用TCP/IP进行网络互连>>第一卷,第二本,第二版查到,由
Prentice-Hall出版.1994.
[3] 关于VPACKET VXD的源代码,可以写信给作者.
chrisc@fir.canberra.edu.au
[4] NAT32是Windows 95下的一个地址翻译包.可从下列网址查到有关信息:
http://willow.canberra.edu.au/~chrisc/nat32.html

http://willow.canberra.edu.au/~chrisc/nat32.html
附录:
IOCTL_PROTOCOL_QUERY_OID
这个操作返回一个特殊目标Object ID.接下来的例子可以实现对当前数据包的过
滤.
BYTE iBuf[sizeof(PACKET_OID_DATA) + 128];
PPACKET_OID_DATA pOidData = (PPACKET_OID_DATA) iBuf;
int result;
memset(iBuf, 0, sizeof(iBuf));
pOidData->Oid = OID_GEN_CURRENT_PACKET_FILTER;
pOidData->Length = 4;
result = ControlPacket((HANDLE) etptr->handle,
IOCTL_PROTOCOL_QUERY_OID,
iBuf,
sizeof(PACKET_OID_DATA) + 4,
iBuf,
sizeof(PACKET_OID_DATA) + 4);
if (result == 12) {
memcpy(arg1, pOidData->Data, 4); /* arg1 is an int * */
return OK;
}
return SYSERR;
The function ControlPacket is listed at the end of this Appendix.
IOCTL_PROTOCOL_STATISTICS
这个操作返回一个特定的适配器状态,它的使用方法与
IOCTL_PROTOCOL_QUERY_OID非常相似,它必须有一个隔离操作,因为底层的NIC所
用的机制不同.
IOCTL_PROTOCOL_RESET
这个操作可以复位底层的适配器(网卡).一般不需要.
IOCTL_PROTOCOL_READ
下面的例子将演示这个操作可以返回一个从网上接受的数据包.
int RcvPacket(HANDLE hVxD,
BYTE* Buffer,
DWORD cbIn)
{
HANDLE hEvent;

HANDLE hEvent;
DWORD cbRet = 0;
OVERLAPPED ovlp = {0,0,0,0,0};
int result;
hEvent = CreateEvent(0, TRUE, 0, NULL);
if (!hEvent)
return SYSERR;
ovlp.hEvent = hEvent;
result = DeviceIoControl(hVxD,
IOCTL_PROTOCOL_READ,
Buffer,
cbIn,
Buffer,
cbIn,
&cbRet,
&ovlp);
if (!result)
GetOverlappedResult(hVxD, &ovlp, &cbRet, TRUE);
CloseHandle(hEvent);
return cbRet;
}
注意:cbIn参数对于以太网必须为1514.
IOCTL_PROTOCOL_WRITE
这个操作可以向网上发送一个数据包,它和IOCTL_PROTOCOL_READ的用法非常类似
注意:这个包必须包含一个完整的包头.
IOCTL_PROTOCOL_MACNAME
这个操作返回一个包含网卡驱动程序名字的字符串.
result = ControlPacket((HANDLE) etptr->handle,
IOCTL_PROTOCOL_MACNAME,
iBuf,
32,
iBuf,
32);
if (result > 0) {
memcpy(arg1, iBuf, result); /* arg1 must be a char * */
return OK;

return OK;
}
return SYSERR;
IOCTL_PROTOCOL_BIND
这个操作将VPACKET绑定到一个特定适配器(网卡),参考前面第五点.
ControlPacket
int ControlPacket(HANDLE hVxD,
ULONG ioctl,
BYTE* inBuffer,
DWORD cbIn,
BYTE* outBuffer,
DWORD cbOut)
{
HANDLE hEvent;
DWORD cbRet = 0;
OVERLAPPED ovlp = {0,0,0,0,0};
int result;
hEvent = CreateEvent(0, TRUE, 0, NULL);
if (!hEvent)
return SYSERR;
ovlp.hEvent = hEvent;
result = DeviceIoControl(hVxD,
ioctl,
inBuffer,
cbIn,
outBuffer,
cbOut,
&cbRet,
&ovlp);
if (!result)
GetOverlappedResult(hVxD, &ovlp, &cbRet, TRUE);
CloseHandle(hEvent);
return cbRet;
}
一个异步从网络上读取数据包的例子
同步输入输出(I/O)一个很大的缺点就是,数据输入和数据处理是连续的.例
如:从网上收到一个数据包,就要在下一个数据包到达之前交给应用程序处理.这
种工作模式在低速设备上可以很好工作,但在高速设备上就会丢失数据包.
VPACKET VXD支持异步读写操作.例如:应用程序可以使得一个操作在实际的
输入输出(I/O)操作结束前就返回.应用程序可以通过一个检查函数在另一个独立
的线程中检查实际输入输出(I/O)是否完成.即使这样,仍然会产生数据包丢失问
题.除非设备有足够大的读入数据缓冲区来防止数据溢出的情况.换句话说,数据
包X被接收下来之后,设备必须能够在数据包X被处理时接收随后而来的数据包
下面给出的例子代码是按照下面所说的方式工作的.
netin函数工作在你的软件初始化时产生的一个独立线程中.netin函数通过调用
几次来首先初始化VPACKET驱动程序.当前版本的VPACKET允许拖延64个为完成操
作,但是这个限制能够通过改变VPACKET.H中的一个常量来很容易的增加.然后重
新编译生成此驱动程序.注意:RcvStart通过调用DeviceIoControl来开始读操作
然后立即返回.
netin然后就会进入一段等待代码,这段代码只有在驱动程序被关闭时才会退出.
同时,这段代码调用WIN32_API函数WaitForMultipleObjectsEx来等待网上数据包
的到来.当数据包真的到来时,就会向更高层的函数传递这个包的指针来供处理(
当arp数据包,rarp数据包,ip数据包到来时).这个高层的函数将这个包的指针加
入队列当中供以后的处理,然后立即返回.紧跟着就调用RcvStart来补充急待处理
的读操作.显然,这种方式很少导致数据包丢失,因为读操作几乎总是一个接一个.
以下就是例子代码:
/* netin.c - netin */
#include <windows.h>
#include "conf.h"
#include "kernel.h"
#include "network.h"
#include "wether.h"
/*------------------------------------------------------------------------
* netin - read packets from an Eth device (non-blocking VPACKET version)
*------------------------------------------------------------------------
*/
COMMAND netin(int nargs, char **args)
{
struct etblk *etptr;
struct ep *pep;
struct ip *pip;

struct ip *pip;
int ps, dev, len, i, j, k;
struct rcvblk rcvtab[RTAB_SIZE];
struct netif *pni;
HANDLE hList[RTAB_SIZE];
Eaddr zero = {0,0,0,0,0,0};

dev = atoi(args[0]);
etptr = ð[devtab[dev].dvminor];

if (!etptr->isopen)
return SYSERR;
/* NOTE: RTAB_SIZE must not be greater than 64 (a WIN32 restriction) */

for (i=0; i<RTAB_SIZE; i++) { /* prime the driver for packet reception */
pep = (struct ep *) getbuf(Net.netpool);
rcvtab[i].pep = pep;
rcvtab[i].len = 1514;
rcvtab[i].active = FALSE;
rcvtab[i].intf = etptr->ifnum;
RcvStart(etptr->handle, &rcvtab[i]);
hList[i] = rcvtab[i].ovlp.hEvent;
}
Net.netin_pid = getpid(); /* save pid of this thread */
signal(Net.sema); /* signal that we're running */

while (etptr->isopen) { /* netin main loop */
i = WaitForMultipleObjectsEx(RTAB_SIZE, hList, FALSE, INFINITE, FALSE);
if (i == WAIT_FAILED) break;
for (j=0; j<RTAB_SIZE; j++)
if (hList[i] == rcvtab[j].ovlp.hEvent) break;
k = j;
if (!etptr->isopen) break; /* exit, device has been closed */
GetOverlappedResult((HANDLE) etptr->handle,
&rcvtab[k].ovlp,
&rcvtab[k].cbRet,

&rcvtab[k].cbRet,
FALSE);
pep = rcvtab[k].pep;
pep->ep_len = rcvtab[k].cbRet; /* record packet length */
pep->ep_ifn = rcvtab[k].intf; /* record interface # */
pni = &nif[pep->ep_ifn];

// The following check for reflected packets really belongs in the VPACKET
// device driver. For most (but not all) NDIS3 drivers the reflected packet
// contains the addr placed in the src addr field by ethwrite, while the
// packet actually transmitted contains the real physical adapter address.
// The packet reflected to OTHER bound protocols also contains the real
// adapter address.
if (net2hs(pep->ep_type) == EPT_IP) {
pip = (struct ip *) pep->ep_data;
if (blkequ(&pip->ip_src, &pni->ni_ip, IP_ALEN)) {
disable(ps);
freebuf(pep);
goto reinit;
}
if (blkequ(&pip->ip_dst, &pni->ni_other, IP_ALEN)) {
disable(ps);
freebuf(pep);
goto reinit;
}
if (!pni->ni_ovalid) {
if (blkequ(&pip->ip_dst, &pni->ni_ip, IP_ALEN))
if (blkequ(pep->ep_src, pni->ni_hwa.ha_addr, EP_ALEN)) {
pni->ni_other = pip->ip_src;
pni->ni_ovalid = 1;
p32send(Net.netstart_pid, OK);
}
}
}
pni->ni_ioctets += pep->ep_len;
if (blkequ(pni->ni_hwa.ha_addr, pep->ep_dst, EP_ALEN))

if (blkequ(pni->ni_hwa.ha_addr, pep->ep_dst, EP_ALEN))
pni->ni_iucast++;
else
pni->ni_inucast++;
pep->ep_type = net2hs(pep->ep_type);
pep->ep_order = EPO_NET;
disable(ps);
switch (pep->ep_type) {
case EPT_ARP: arp_in(&nif[etptr->ifnum], pep); break;
case EPT_RARP: rarp_in(&nif[etptr->ifnum], pep); break;
case EPT_IP: ip_in(&nif[etptr->ifnum], pep); break;
default:
pni->ni_iunkproto++;
freebuf(pep);
}

reinit: CloseHandle((HANDLE) rcvtab[k].ovlp.hEvent);
rcvtab[k].active = FALSE;
restore(ps);
pep = (struct ep *) getbuf(Net.netpool); /* use getbufi */
disable(ps);
/* move all handles up by one to make space at the end for a new one */
for (j=i; j<RTAB_SIZE-1; i++)
hList[i] = hList[++j];

rcvtab[k].pep = pep;
rcvtab[k].len = 1514;
RcvStart(etptr->handle, &rcvtab[k]);
hList[RTAB_SIZE-1] = rcvtab[k].ovlp.hEvent; // add to end of list
restore(ps);
}
/* if we ever get here, someone has closed the device */
for (i=0; i<RTAB_SIZE; i++) /* delete events and buffers */
if (rcvtab[i].active) {
CloseHandle((HANDLE) rcvtab[i].ovlp.hEvent);
freebuf(rcvtab[i].pep);

freebuf(rcvtab[i].pep);
rcvtab[i].active = FALSE;
}
return SYSERR; /* netin will terminate */
}
LOCAL RcvStart(HANDLE hVxD,
struct rcvblk *prb)
{
HANDLE hEvent;
int result;
hEvent = CreateEvent(0, TRUE, 0, NULL); /* manual reset */
prb->ovlp.Internal = 0;
prb->ovlp.InternalHigh = 0;
prb->ovlp.Offset = 0;
prb->ovlp.OffsetHigh = 0;
prb->ovlp.hEvent = hEvent;
prb->cbRet = 0;
if (!hEvent)
return SYSERR;

result = DeviceIoControl(hVxD,
IOCTL_PROTOCOL_READ,
&prb->pep->ep_eh,
prb->len,
&prb->pep->ep_eh,
prb->len,
&prb->cbRet,
&prb->ovlp);
if (result)
return SYSERR; /* operation completed or something went wrong */
prb->active = TRUE;
return OK; /* operation is pending */
}
--
lixuyu 2001-09-13
  • 打赏
  • 举报
回复
那就只好用别人开发的驱动罗。
CDSoftwareWj 2001-09-13
  • 打赏
  • 举报
回复
我知道的一些是用VxD开发驱动程序来实现监听TCP/IP数据包的,不知道用什么方法可以不用开发驱动来作到??
YHW 2001-09-13
  • 打赏
  • 举报
回复
gz
Suddy 2001-09-13
  • 打赏
  • 举报
回复
Commview 这个软件实现了这个功能
zepczy 2001-09-13
  • 打赏
  • 举报
回复
用一个大循环不断地侦听IP地址,用小循环不断地侦听端口,然后把这些SOCKET置于LISTEN状态!
cctime 2001-09-13
  • 打赏
  • 举报
回复
IpMon,不用driver,
sock_raw,加一个设置字,等会详细贴出来
peterxu 2001-09-13
  • 打赏
  • 举报
回复
我也好想知道
ray2_ls 2001-09-13
  • 打赏
  • 举报
回复
偶也想知道啦
poweruser 2001-09-13
  • 打赏
  • 举报
回复
以前的贴子倒是有关于这方面的,但是没有详细的原理
你自己找找吧
jsd198 2001-09-13
  • 打赏
  • 举报
回复
我还想知道呢

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧