NetBIOS网络编程
“网络基本输入/输出系统”(Network Basic Input/Output System,NetBIOS)是1983年由Sytex公司为IBM公司开发的一种标准应用程序编程接口,并被微软采用。1985年,IBM改进了NetBIOS,推出了NetBIOS扩展用户接口(NetBIOS Extended User Interface,NetBEUI)通信协议,它占用内存少,配置简单,适用于小型局域网不同计算机之间的通信,但不具有跨网段工作的能力,不支持路由机制。NetBIOS是一种与“协议无关”的编程接口,它使应用程序不用理解网络细节,应用程序可通过TCP/IP、NetBEUI、SPX/IPX运行。
它定义了一种软件接口以及在应用程序连接介质之间提供通信接口的标准方法,它可以人提供名字服务、会话服务和数据库服务,基于NetBIOS的比较典型的应用是远程计算机的Mac地址、名称和所在工作组等信息。
PS:网上很多说NetBIOS网络编程已经过时了,不过还是稍做了解吧~
(以下为个人概括的五点,如有什么不是很对的地方,欢迎指正)
重点1:它是基于会话层的服务。
重点2:它可以让两台机器相互连接,建立通信。
重点3:它可以基于UDP或者TCP实现。
重点4:实现这个NetBIOS与基本的TCP/IP编程的最大不同点就是向另一台机发送的是NetBIOS请求包,接收的是NetBIOS回应包,然后对NetBIOS回应包进行解释,其编程思路与TCP/IP编程基本相似,只是一些recv和send的东西不同。
重点5: 它的实现,也可以在“cmd”中使用nbtstat指令体现。
下面是三个与NetBIOS网络编程稍有关系的实例应用:
01. GetNetBIOSNames.cpp -- 获取LANA上所有NetBIOS名字
02. GetMacAddress.cpp -- 获取网络适配器上的MAC地址
03. NbtStat.cpp -- 获取网络中指定计算机的基本信息
源代码:
01. GetNetBIOSNames.cpp -- 获取LANA上所有NetBIOS名字
[cpp] view plaincopyprint?
01.// GetNetBIOSNames.cpp -- 获取LANA上所有NetBIOS名字
02.
03.#include <windows.h>
04.#include <stdlib.h>
05.#include <stdio.h>
06.#include <Nb30.h>
07.
08.#pragma comment(lib, "netapi32.lib")
09.
10.// Set LANANUM and LOCALNAME as appropriate for your system
11.#define LANANUM 0
12.#define LOCALNAME "UNIQUENAME"
13.#define NBCheck(x) if (NRC_GOODRET != x.ncb_retcode) { \
14. printf("Line %d: Got 0x%x from NetBios()\n", \
15. __LINE__, x.ncb_retcode); \
16. }
17.
18.void MakeNetbiosName (char *, LPCSTR);
19.BOOL NBReset (int, int, int);
20.BOOL NBAddName (int, LPCSTR);
21.BOOL NBListNames (int, LPCSTR);
22.BOOL NBAdapterStatus (int, PVOID, int, LPCSTR);
23.
24.int main()
25.{
26. // 初始化,清空本地名字表和会话表
27. if (!NBReset (LANANUM, 20, 30)){
28. return -1;
29. }
30. // 向本地名字表中添加UNIQUENAME
31. if (!NBAddName (LANANUM, LOCALNAME)) {
32. return -1;
33. }
34. // 列出本地名字表中的名字
35. if (!NBListNames (LANANUM, LOCALNAME)) {
36. return -1;
37. }
38. printf ("Succeeded.\n");
39. system("pause");
40. return 0;
41.}
42.
43./**
44. * NCB结构体的定义:
45. * typedef struct _NCB{
46. * UCHAR ncb_command; // 指定命令编码以及表明NCB结构体是否被异步处理的标识
47. * UCHAR ncb_retcode; // 指定命令的返回编码
48. * UCHAR ncb_lsn; // 表示本地会话编号,在指定环境中此编号唯一标识一个会话
49. * UCHAR ncb_num; // 指定本地网络名字编号。
50. * PUCHAR ncb_buffer; // 指定消息缓冲区。(有发送信息、接收信息、接收请求状态信息三个缓冲区)
51. * WORD ncb_length; // 指定消息缓冲区的大小,单位为字节。
52. * UCHAR ncb_callname[NCBNAMSZ]; // 指定远程端应用程序的名字
53. * UCHAR ncb_name[NCBNAMSZ]; // 指定应用程序可以识别的名字
54. * UCHAR ncb_rto; // 指定会话执行接收操作的超时时间
55. * void (CALLBACK * ncb_post)(struct NCB);
56. * UCHAR ncb_lana_num; // 指定LANA编号
57. * UCHAR ncb_cmd_cplt; // 指定命令完成标识
58. * UCHAR ncb_reserve[X]; // 保留字段
59. * HANDLE ncb_event; // 指向事件对象的句柄
60. * }NCB, *PNCB;
61. **/
62.
63.
64.// 清空本地名字和会话表
65.BOOL NBReset (int nLana, int nSessions, int nNames)
66.{
67. NCB ncb;
68. memset (&ncb, 0, sizeof (ncb)); // 清空ncb结构体
69. ncb.ncb_command = NCBRESET; // 执行NCBRESET命令,复位局域网网络适配器,清空指定LANA编号上定义的本地名字表和会话表。
70. ncb.ncb_lsn = 0; // 分配新的lana_num资源,Netbios()函数成功执行了NCBCALL命令后返回的编号
71. ncb.ncb_lana_num = nLana; // 设置lana_num资源,指定本地网络名字编号。
72. ncb.ncb_callname[0] = nSessions; // 设置最大会话数
73. ncb.ncb_callname[2] = nNames; // 设置最大名字数
74. Netbios (&ncb); // 执行NCBRESET命令
75. NBCheck (ncb); // 如果执行结果不正确,则输出ncb.ncb_retcode
76. // 如果成功返回TRUE,否则返回FALSE
77. return (NRC_GOODRET == ncb.ncb_retcode);
78.}
79.
80.
81.// 向本地名字表中添加名字
82.BOOL NBAddName (int nLana, LPCSTR szName)
83.{
84. NCB ncb;
85. memset (&ncb, 0, sizeof (ncb)); // 清空ncb结构体
86. ncb.ncb_command = NCBADDNAME; // 执行NCBDDNAME命令,向本地名字表中添加一个唯一的名字
87. ncb.ncb_lana_num = nLana; // 设置lana_num资源,指定本地网络名字编号。
88. MakeNetbiosName ((char*) ncb.ncb_name, szName); // 将szName赋值到ncb.ncb_name中
89. Netbios (&ncb); // 执行NCBRESET命令
90. NBCheck (ncb); // 如果执行结果不正确,则输出ncb.ncb_retcode
91. // 如果成功返回TRUE,否则返回FALSE
92. return (NRC_GOODRET == ncb.ncb_retcode);
93.}
94.
95.
96.// Build a name of length NCBNAMSZ, padding with spaces.
97.// 将szSrc中的名字赋值到achDest中,名字的长度为NCBNAMESZ
98.// 如果不足,则使用空格补齐
99.void MakeNetbiosName (char *achDest, LPCSTR szSrc)
100.{
101. int cchSrc = strlen ((char*)szSrc); // 取名字的长度
102. if (cchSrc > NCBNAMSZ){
103. cchSrc = NCBNAMSZ;
104. }
105. memset (achDest, ' ', NCBNAMSZ);
106. memcpy (achDest, szSrc, cchSrc);
107.}
108.
109.// 列出指定LANA上所有的名字
110.BOOL NBListNames (int nLana, LPCSTR szName)
111.{
112. int cbBuffer; // 获取数据的缓冲区
113. ADAPTER_STATUS *pStatus; // 保存网络适配器的信息
114. NAME_BUFFER *pNames; // 保存本地名字信息
115. HANDLE hHeap; // 当前调用进程的堆句柄
116.
117. hHeap = GetProcessHeap(); // 当前调用进程的堆句柄
118. cbBuffer = sizeof (ADAPTER_STATUS) + 255 * sizeof (NAME_BUFFER);// 分配可能的最大缓冲区空间
119. pStatus = (ADAPTER_STATUS *) HeapAlloc (hHeap, 0, cbBuffer);// 为pStatus分配空间
120. if (NULL == pStatus){
121. return FALSE;
122. }
123. // 获取本地网络适配器信息,结果保存到pStatus中
124. if (!NBAdapterStatus (nLana, (PVOID) pStatus, cbBuffer, szName)){
125. HeapFree (hHeap, 0, pStatus);
126. return FALSE;
127. }
128. // 列出跟在ADAPTER_STATUS结构体后面的名字信息
129. pNames = (NAME_BUFFER *) (pStatus + 1);
130. for (int i = 0; i < pStatus->name_count; i++){
131. printf ("\t%.*s\n", NCBNAMSZ, pNames[i].name);
132. }
133.
134. HeapFree (hHeap, 0, pStatus);// 释放分配的堆空间
135.
136. return TRUE;
137.}
138.
139.// 获取指定LANA的网络适配器信息
140.// nLana, LANA编号
141.// pBuffer, 获取到的网络适配器缓冲区
142.// cbBuffer, 缓冲区长度
143.// szName, 主机名字
144.BOOL NBAdapterStatus (int nLana, PVOID pBuffer, int cbBuffer, LPCSTR szName)
145.{
146. NCB ncb;
147. memset (&ncb, 0, sizeof (ncb)); // 清空ncb结构体
148. ncb.ncb_command = NCBASTAT; // 设置执行NCBASTAT命令,获取本地或远程网络适配器的状态
149. ncb.ncb_lana_num = nLana; // 设置LANA编号
150.
151. ncb.ncb_buffer = (PUCHAR) pBuffer; // 将获取到的数据保存到参数pBuffer中
152. ncb.ncb_length = cbBuffer; // 设置缓冲区长度
153.
154. MakeNetbiosName ((char*) ncb.ncb_callname, szName);// 设置参数ncb.ncb_callname
155. Netbios (&ncb); // 执行NetBIOS命令
156. NBCheck (ncb); // 如果执行不成功,则输出返回值
157. // 如果成功返回TRUE,否则返回FALSE
158. return (NRC_GOODRET == ncb.ncb_retcode);
159.}
02. GetMacAddress.cpp -- 获取网络适配器上的MAC地址
[cpp] view plaincopyprint?
01.// GetMacAddress.cpp -- 获取网络适配器上的MAC地址
02.
03.#include <stdio.h>
04.#include <stdlib.h>
05.#include <windows.h>
06.#include <Nb30.h>
07.
08.#pragma comment(lib, "netapi32.lib")
09.
10.
11./**
12. * ADAPTER_STATUS结构体中包含网络适配器的信息
13. * typedef struct _ADAPTER_STATUS{
14. * UCHAR adapter_address[6]; // 指定网络适配器的地址
15. * UCHAR rev_major; // 指定发布软件的主版本号
16. * UCHAR reserved0; // 保留字段,始终为零
17. * UCHAR adapter_type; // 指定网络适配器的类型
18. * UCHAR rev_minor; // 指定发布软件的副版本号
19. * WORD duration; // 指定报告的时间周期,单位为分钟
20. * WORD frmr_recv; // 指定接收到的FRMR(帧拒绝)帧数量
21. * WORD frmr_xmit; // 指定传送的FRMR帧数量
22. * WORD iframe_recv_err; // 指定接收到的错误帧数量
23. * WORD xmit_aborts; // 指定终于传输的包数量
24. * DWORD xmit_success; // 指定成功传输的包数量
25. * DWORD recv_success; // 指定成功接收的包数量
26. * DWORD iframe_xmit_err; // 指定传输的错误帧数量
27. * WORD recv_buf_unavail; // 指定缓冲区无法为远程计算机提供服务次数
28. * WORD tl_timeouts; // 指定DLC(Data Link Control, 数据链路控制)T1计数器超时的次数
29. * WORD ti_timeouts; // 指定ti非活动计时器超时的次数。ti计时器用于检测断开的连接
30. * DWORD reservedl; // 保留字段,始终为0
31. * WORD free_ncbs; // 指定当前空闲的网络控制块的数量
32. * WORD max_cfg_ncbs; // 最大网络控制块数据包的大小
33. * WORD max_ncbs; // 最大网络控制块的数量
34. * WORD xmit_buf_unavail; // 不可用的传输包的缓冲区
35. * WORD max_dgram_size; // 包的最大值
36. * WORD pending_sess; // 指定挂起会话的数量
37. * WORD max_cfg_sess; // 指定数据包的最大大小,该值至少为512字节
38. * WORD max_sess; // 最大数量
39. * WORD max_sess_pkt_size; // 指定会话数据包的最大大小
40. * WORD name_count; // 指定本地名字表中名字的数量
41. * }ADAPTER_STATUS, *PADAPTER_STATUS;
42. **/
43.
44.
45.// 结构体ASTAT用于定义网络适配器状态和名字表信息
46.typedef struct _ASTAT_
47.{
48. ADAPTER_STATUS adapt; // 网络适配器状态
49. NAME_BUFFER NameBuff [30]; // 名字表信息
50.}ASTAT, * PASTAT;
51.
52.ASTAT Adapter;
53.
54.int main()
55.{
56. NCB ncb; // NCB结构体,用于设置执行的NetBIOS命令和参数
57. UCHAR uRetCode; // 执行Netbios()函数的返回值
58. memset( &ncb, 0, sizeof(ncb) ); // 初始化ncb结构体
59. ncb.ncb_command = NCBRESET; // 设置执行NCBRESET,复位网络适配器
60. ncb.ncb_lana_num = 0; // 设置LANA编号
61.
62. uRetCode = Netbios( &ncb ); // 调用Netbios()函数,执行NCBRESET命令
63. // 输出执行NCBRESET命令的结果
64. printf( "The NCBRESET return code is: 0x%x \n", uRetCode );
65.
66. memset( &ncb, 0, sizeof(ncb) ); // 初始化ncb
67. ncb.ncb_command = NCBASTAT; // 执行NCBASTAT命令,获取网络适配器状态
68. ncb.ncb_lana_num = 0; // 设置LANA编号
69. // 设置执行NCBASTAT命令的参数,将获取到的网络适配器数据保存到Adapter结构体中
70. memcpy( &ncb.ncb_callname, "* ", 16 );
71. ncb.ncb_buffer = (UCHAR*) &Adapter;
72. ncb.ncb_length = sizeof(Adapter);
73. uRetCode = Netbios( &ncb ); // 调用Netbios()函数,执行NCBASTAT命令
74. printf( "The NCBASTAT return code is: 0x%x \n", uRetCode );
75. if ( uRetCode == 0 ) { // 输出MAC地址
76. printf( "The Ethernet Number is: %02x-%02x-%02x-%02x-%02x-%02x\n",
77. Adapter.adapt.adapter_address[0],
78. Adapter.adapt.adapter_address[1],
79. Adapter.adapt.adapter_address[2],
80. Adapter.adapt.adapter_address[3],
81. Adapter.adapt.adapter_address[4],
82. Adapter.adapt.adapter_address[5] );
83. }
84. system("pause");
85. return 0;
86.}
03. NbtStat.cpp -- 获取网络中指定计算机的基本信息