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 -- 获取网络中指定计算机的基本信息

[cpp] view plaincopyprint?
01.// NbtStat.cpp -- 获取网络中指定计算机的基本信息
02.
03.#include <string.h>
04.#include <stdio.h>
05.#include <winsock2.h>
06.#include <map>
07.
08.#pragma comment(lib, "Ws2_32.lib")
09.
10.using namespace std;
11.
12.
13.class CDevice
14.{
15.public:
16.    CDevice(void){}
17.    CDevice(string ip):IP(ip), Name (""), Mac(""), Workgroup(""){}
18.
19.public:
20.    ~CDevice(void){}
21.
22.public:
23.    string IP;          // IP地址
24.    string Name;        // 名称
25.    string Mac;         // Mac地址
26.    string Workgroup;   // 工作组
27.};
28.
29.
30.
31.// 通过NbtStat获取计算机名字信息的结构体
32.struct names
33.{
34.    unsigned char nb_name[16];  // 表示接收到的名字
35.    unsigned short name_flags;  // 标识名字的含义
36.};
37.
38.
39.// 保存获取NetBIOS信息的Socket和IP地址列表
40.struct workstationNameThreadStruct
41.{
42.    SOCKET s;                   // 指定发送和接收NetBIOS数据包的Socket
43.    std::map<unsigned long, CDevice*> *ips;   // 指定获取NetBIOS信息的IP地址列表
44.};
45.
46.// 格式化ethernet中的字节为字符串
47.void GetEthernetAdapter(unsigned char *ethernet, char *macstr)
48.{
49.    sprintf(macstr, "%02x %02x %02x %02x %02x %02x",
50.        ethernet[0],    ethernet[1],        ethernet[2],
51.        ethernet[3],    ethernet[4],        ethernet[5]
52.    );
53.    return;
54.}
55.
56.
57.// 获取设备的名称和MAC地址等信息
58./**
59. * GetHostInfo()函数的运行过程
60. * 创建发送和接收NetBIOS数据包的Socket, 并将其绑定在本地地址的端口0上。
61. * 创建接收NetBIOS回应包的线程,参数unionStruct中包含要获取NetBIOS信息的IP地址和通信用的Socket。
62. * 使用for循环语句依次向每个IP地址发送NetBIOS请求包,请求包数据保存在字符数组input中。
63. * 调用WaitForSingleObject()函数,等待接收线程结束。
64. * 如果超时,则结束接收线程NetBiosRecvThreadProc()函数。
65. * 关闭线程句柄,释放资源。
66. **/
67.void GetHostInfo(std::map<unsigned long, CDevice*> &ips, int timeout)
68.{
69.    DWORD WINAPI NetBiosRecvThreadProc(void *param);
70.
71.    const int defaultPort = 0;      // 设定默认的绑定端口
72.    SOCKET sock;                    // 通信套接字
73.    struct sockaddr_in origen;      // 本地地址
74.    WSADATA wsaData;                // Windows Sockets环境变量
75.
76.    if(WSAStartup(MAKEWORD(2,1),&wsaData) != 0){// 初始化Windows Sockets环境
77.        return;
78.    }
79.    if(INVALID_SOCKET ==(sock = socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP))){// 创建TCP/IP套接字
80.        return;
81.    }
82.    // 设置超时时间
83.    if(SOCKET_ERROR ==setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout))){
84.        closesocket(sock);
85.        WSACleanup();
86.        return;
87.    }
88.    // 将套接字绑定到本地地址和端口0
89.    memset(&origen, 0, sizeof(origen));
90.    origen.sin_family = AF_INET;
91.    origen.sin_addr.s_addr = htonl (INADDR_ANY);
92.    origen.sin_port = htons (defaultPort);
93.    if (bind (sock, (struct sockaddr *) &origen, sizeof(origen)) < 0) { // 套接字连接
94.        closesocket(sock);
95.        WSACleanup();
96.        return;
97.    }
98.
99.    // 为创建接收线程准备数据
100.    workstationNameThreadStruct unionStruct;
101.    unionStruct.ips = &ips;
102.    unionStruct.s = sock;
103.    // 启动线程等待接收NetBIOS回应包
104.    DWORD pid;
105.    HANDLE threadHandle = CreateThread(NULL, 0, NetBiosRecvThreadProc,(void *)&unionStruct, 0, &pid);
106.
107.    // 依次向ips中的每个IP地址的137端口发送NetBIOS请求包(保存在input字符数组中)
108.    std::map<unsigned long, CDevice*>::iterator itr;
109.    for(itr=ips.begin();itr != ips.end();itr++)
110.    {
111.        char input[]="\x80\x94\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x20\x43\x4b\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00\x00\x21\x00\x01";
112.        struct sockaddr_in dest;
113.        // 发送NetBios请求信息
114.        memset(&dest,0,sizeof(dest));
115.        dest.sin_addr.s_addr = itr->first;
116.        dest.sin_family = AF_INET;
117.        dest.sin_port = htons(137);
118.        sendto (sock, input, sizeof(input)-1, 0, (struct sockaddr *)&dest, sizeof (dest));
119.    }
120.    // 等待接收线程NetBiosRecvThreadProc结束
121.    DWORD ret = WaitForSingleObject(threadHandle, timeout * 4);
122.    // 如果超时,则结束接收线程NetBiosRecvThreadProc
123.    if(ret == WAIT_TIMEOUT){
124.        TerminateThread(threadHandle, 0);
125.    }
126.    else{
127.        printf("thread success exit\n");
128.    }
129.    // 关闭线程句柄
130.    CloseHandle(threadHandle);
131.
132.    // 释放资源
133.    closesocket(sock);
134.    WSACleanup();
135.}
136.
137.
138.
139.
140.// 获取计算机名称以及MAC地址的函数线程
141./**
142. * NetBiosRecvThreadProc()函数运行过程
143. * 在while循环中调用recvfrom()函数,在套接字sock上接收数据.
144. * 如果超时,则多重试两次。
145. * NetBIOS回应包的前56位是网络适配器状态信息,第57位保存名字表中名字的数量。
146. * 依次处理名字表中每个名字项,如果最后一位是0x00,则表示当前名字项用于保有存计算机名或者工作组。
147. *  name_flags字段可以区分当前名字是计算机名还是工作组。
148. * 在NetBIOS回应包中,包字表后面的6个字节是计算机的MAC地址。
149. *   调用GetEthernetAdapter()函数可以将其转换为字符串。
150. * 将获取到的计算机名、工作组和MAC地址保存到ips映射表项中的CDevice对象中。
151. **/
152.
153.DWORD WINAPI NetBiosRecvThreadProc(void *param)
154.{
155.    char respuesta[1000];                   // 保存接收到的NetBIOS
156.    unsigned int count=0;                   // 用于在NetBIOS回应包中定位名字数组的位置
157.    unsigned char ethernet[6];          // 保存MAC地址
158.    struct sockaddr_in from;                // 发送NetBIOS回应包
159.    // 参数是要获取NetBIOS信息的IP地址和套接字
160.    workstationNameThreadStruct *unionStruct = (workstationNameThreadStruct *)param;
161.    SOCKET sock = unionStruct->s;    // 用于接收NetBIOS回应包的套接字
162.    // 要获取NetBIOS信息的IP地址
163.    std::map<unsigned long, CDevice*> *ips = unionStruct->ips;
164.    int len = sizeof (sockaddr_in);     // 地址长度
165.    // 定义名字数组
166.    struct names Names[20*sizeof(struct names)];
167.
168.    int ipsCount = ips->size();          // 要获取NetBIOS信息的IP地址数量
169.    int timeoutRetry = 0;                   // 记录超时重试的次数
170.    while(true){
171.        count = 0;
172.        // 在套接字sock上接收消息
173.        int res= recvfrom (sock, respuesta, sizeof(respuesta), 0, (sockaddr *)&from, &len);
174.        // 如果超时,则重试,但重试次数不超过两次
175.        if(res == SOCKET_ERROR) {
176.            if(GetLastError() == 10060) {
177.                timeoutRetry++;
178.                if(timeoutRetry == 2)
179.                    break;
180.            }
181.            continue;
182.        }
183.        if(res <= 121){
184.            continue;
185.        }
186.
187.        // 将count定位到名字表中名字的数量。在NetBIOS回应包中,前面56位是网络适配器的状态信息
188.        memcpy(&count, respuesta+56, 1);
189.        if(count > 20){      // 最多有20个名字,超出则错误
190.            continue;
191.        }
192.
193.        // 将名字表内在复制到Names数组中
194.        memcpy(Names,(respuesta+57), count*sizeof(struct names));
195.
196.        // 将空格字符替换成空
197.        for(unsigned int i = 0; i < count;i++) {
198.            for(unsigned int j = 0;j < 15;j++){
199.                if(Names[i].nb_name[j] == 0x20)
200.                    Names[i].nb_name[j]=0;
201.            }
202.        }
203.
204.        string mac;
205.        // 如果发送回应包的地址在ips中,则处理该包
206.        std::map<unsigned long, CDevice*>::iterator itr;
207.        if( (itr = ips->find(from.sin_addr.S_un.S_addr)) != ips -> end()){
208.            // 获取发送NetBIOS回应包的IP地址
209.            in_addr inaddr;
210.            inaddr.S_un.S_addr = itr->first;
211.            itr->second->IP = inet_ntoa(inaddr);
212.            // 处理名字表中的所有名字
213.            for(int i=0;i<count;i++){
214.                // 如果最后一位是0x00,则表示当前名字表项为保存计算机名或者工作组
215.                if(Names[i].nb_name[15] == 0x00){
216.                    char buffers[17] = {0};
217.                    memcpy(buffers, Names[i].nb_name, 16);
218.                    // 使用name_flags字段来区分当前名字是计算机名还是工作组
219.                    if((Names[i].name_flags & 128) == 0) {
220.                        itr->second->Name = buffers;
221.                    }
222.                    else{
223.                        itr->second->Workgroup = buffers;
224.                    }
225.                }
226.                // 名字表后面是MAC地址
227.                memcpy(ethernet,(respuesta+57+count*sizeof(struct names)),6);
228.                char mac[20] = {0};
229.                // 格式化MAC地址
230.                GetEthernetAdapter(ethernet,mac);
231.                itr->second->Mac = mac;
232.            }
233.        }
234.    }
235.
236.    return 0;
237.}
238.
239.
240.
241.int main()
242.{
243.    std::map<unsigned long, CDevice*> ips;
244.    // 向ips中添加一个设备
245.    CDevice dev1("10.5.1.5");
246.    unsigned long ip1 = inet_addr(dev1.IP.c_str());
247.    ips.insert(make_pair(ip1, &dev1));
248.    // 向ips中添加第2个设备
249.    CDevice dev2("10.10.10.1");
250.    unsigned long ip2 = inet_addr(dev2.IP.c_str());
251.    ips.insert(make_pair(ip2, &dev2));
252.
253.    // 获取设备信息
254.    GetHostInfo(ips, 2000);
255.    std::map<unsigned long, CDevice*>::iterator itr;
256.    for(itr = ips.begin(); itr != ips.end(); itr++)
257.    {
258.        printf("\nIP: %s;  \nName: %s;  \nMac: %s;  \nWorkgroup:  %s\n\n",
259.            itr->second->IP.c_str(), itr->second->Name.c_str(), itr->second->Mac.c_str(), itr->second->Workgroup.c_str());
260.    }
261.    system("pause");
262.    return 0;
263.}

NetBIOS网络编程相关推荐

  1. NetBios网络基础及编程

    开始学习(算是复习)网络编程了,第一个就是局域网的netbios协议编程. 首先了解一下什么是netbios:IBM公司为PC-Network开发的一套网络标准.,NetBIOS最广泛的应用之一就是对 ...

  2. JavaSE学习笔记之网络编程

    网络基础 网络模型 网络模型一般是指OSI七层参考模型和TCP/IP四层参考模型.这两个模型在网络中应用最为广泛. OSI模型,即开放式通信系统互联参考模型(Open System Interconn ...

  3. 2014阿里巴巴实习生招聘-研发工程师笔试题/网络编程小结

    一.单选 1.假设一个主机ip为192.168.5.121,子网掩码为255.255.255.248,则该主机的网络号部分(包括子网号部分)为-- A.192.168.5.12  B 192.168. ...

  4. Java Review(三十八、网络编程)

    文章目录 网络基础 IP地址 端口 域名 网络模型 常用协议 Java 的基本网络支持 使用 InetAddress URL. URLConnection 和 URLPermission 基于TCP协 ...

  5. Linux高并发服务器开发---笔记4(网络编程)

    0705 第4章 项目制作与技能提升 4.0 视频课链接 4.1 项目介绍与环境搭建 4.2 Linux系统编程1.4.3 Linux系统编程2 4.4 多进程 1-9 10.进程间通信☆☆☆ 4.5 ...

  6. 网络编程java_网络编程基础

    在学习Java网络编程之前,我们先来了解什么是计算机网络. 计算机网络是指两台或更多的计算机组成的网络,在同一个网络中,任意两台计算机都可以直接通信,因为所有计算机都需要遵循同一种网络协议. 那什么是 ...

  7. Java基础——网络编程

    一.网路编程知识 意义:过去我们IO流是把本地的文件传递而已,网络编程是把自己电脑的数据传递给另一台电脑,并且回馈信息.这是数据通讯 1.通讯三要素 1.1 IP地址 (1)获取对方主机IP 1.2 ...

  8. Java网络编程--网络基础

    文章目录 网络协议 常用网络协议族(簇)(protocol) 端口(port) 常见知名端口 动态端口 IP地址 IP地址分类 IPv4的分类 IPv6 子网掩码 网络协议 是为计算机网络中进行数据交 ...

  9. JAVA 网络编程基础

    一,前言 了解计算机网络的概述,掌握Sokcet类编程,ServerSocket类,Socket类的构造方法和常用方法 二,计算机网咯 1.概述 计算机网络计算机们组成的网络,同一个网络中,计算机可以 ...

最新文章

  1. 使嵌入式系统调试更容易:有用的硬件和软件提示
  2. python递归_纯Python递归计算行列式
  3. 【AngularJs】获取URL查询参数
  4. Python 图像处理篇-利用opencv库展示本地图片实例演示
  5. Python教程:内置函数filter()和匿名函数lambda解析
  6. Effective C# 原则1:尽可能的使用属性(property),而不是数据成员(field)。
  7. react实现路由跳转_react实现hash路由
  8. 光栅衍射C语言程序,基于matcom的光栅衍射仿真程序
  9. bzoj 3580 冒泡排序 乱搞+思维
  10. oracle 手动执行作业,ORACLE 作业操作
  11. MyEclipse + Maven开发springMVC的WEB工程的详细配置过程
  12. ubuntu安装nvidia显卡驱动+cuda+cudnn
  13. 金蝶连服务器显示演示版,金蝶正版和金蝶演示版的区别
  14. Python+tkinter动态显示与隐藏窗口上的组件
  15. 计算机专业暑期三下乡活动方案,暑期三下乡活动方案
  16. 【JS】388- 深入了解强大的 ES6 「 ... 」 运算符
  17. 关于then()方法的理解
  18. 【Hive任务优化】—— Map、Reduce数量调整
  19. 1688图片搜索淘宝商品接口
  20. 定制一个erp系统多少钱-【揭秘erp开发报价及开发步骤】

热门文章

  1. Windows系统补丁管理工具
  2. SSTI原理以及ctf.show的SSTI(web361-web362)
  3. 30多个DVR品牌现新漏洞,或致永久性Mirai感染
  4. HDU1087 - Super Jumping! Jumping! Jumping! (Java)
  5. vue+webpack在“双十一”导购产品的技术实践
  6. jquery uploadify IE下使用刷新页面时出现SCRIPT5007: 缺少对象
  7. Qt使用QSettings读写ini文件
  8. 骨传导耳机有啥用、戴着耳朵不疼的蓝牙耳机
  9. AUTOSAR Partial Network Configuration
  10. 初中计算机教室简介,初级中学简介