Posted on 2012-01-20 15:04
Seed-L 阅读(310)
评论(1) 编辑 收藏 引用
1
//程序清单2-3 异步事件服务器(Evnbsvr.c)
2
// 编译命令:cl -o Evnbsvr.exe Evnbsvr.c ..\Common\Nbcommon.obj Netapi32.lib
3
//
4
#include <windows.h>
5
#include <stdio.h>
6
#include <stdlib.h>
7
8
#include "nbcommon.h"
9
#include<string.h>
10
11
#define MAX_SESSIONS 254
12
#define MAX_NAMES 254
13
#define MAX_BUFFER 2048
14
#define SERVER_NAME "TEST-SERVER-1"
15
16
17
NCB *g_Clients=NULL; // Global NCB structure for clients
18
19
DWORD WINAPI ClientThread(PVOID lpParam) ;
20
21
int Listen(PNCB pncb, int lana, char *name) ;
22
23
24
25
//PS:/*要补上连接库netapi32.lib,在工程设置里*/
26
27
28
29
//
30
// 函数:main
31
//
32
// 说明:
33
// 初始化NetBIOS 接口,分配一些资源,并且使用事件在每个LANA 上产生异步监听,等待触发
34
// 事件,然后处理客户端连接
35
//
36
int main(int argc, char **argv)
37

{
38
PNCB pncb=NULL;
39
HANDLE hArray[64],
40
hThread;
41
DWORD dwHandleCount=0,
42
dwRet,
43
dwThreadId;
44
int i,
45
num;
46
LANA_ENUM lenum;
47
48
printf("主函数开始执行\n") ;
49
50
if (LanaEnum(&lenum) != NRC_GOODRET)
51
return 1;
52
53
if (ResetAll(&lenum, (UCHAR)MAX_SESSIONS, (UCHAR)MAX_NAMES,
54
FALSE) != NRC_GOODRET)
55
return 1;
56
// 分配一个NCB 结构体数组
57
g_Clients = (PNCB)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
58
sizeof(NCB) * lenum.length);
59
// 创建事件,为每个LANA 添加服务器名,并且异步监听每个LANA
60
for(i = 0; i < lenum.length; i++)
61
{
62
printf("添加第%d个LANA\n",i+1) ;
63
64
hArray[i] = g_Clients[i].ncb_event = CreateEvent(NULL, TRUE,FALSE, NULL);
65
AddName(lenum.lana[i], SERVER_NAME, &num);
66
Listen(&g_Clients[i], lenum.lana[i], SERVER_NAME);
67
}
68
while (1)
69
{
70
// 等待直到客户端连接
71
printf("开始等待连接\n") ;
72
73
74
dwRet = WaitForMultipleObjects(lenum.length, hArray, FALSE,
75
INFINITE);
76
if (dwRet == WAIT_FAILED)
77
{
78
printf("ERROR: WaitForMultipleObjects: %d\n",
79
GetLastError());
80
break;
81
}
82
83
printf("有连接了\n") ;
84
85
// 遍历所有NCB 结构体,如果ncb_cmd_plt 不是NRC_PENDING,说明还有一个客户端,
86
// 为它创建线程并为线程分配新的NCB 结构体,我们需要为其它客户端连接重用原来的NCB
87
for(i = 0; i < lenum.length; i++)
88
{
89
if (g_Clients[i].ncb_cmd_cplt != NRC_PENDING)
90
{
91
pncb = (PNCB)GlobalAlloc(GMEM_FIXED, sizeof(NCB));
92
memcpy(pncb, &g_Clients[i], sizeof(NCB));
93
pncb->ncb_event = 0;
94
hThread = CreateThread(NULL, 0, ClientThread,
95
(LPVOID)pncb, 0, &dwThreadId);
96
CloseHandle(hThread);
97
// 重设句柄并且产生另一个监听
98
ResetEvent(hArray[i]);
99
Listen(&g_Clients[i], lenum.lana[i], SERVER_NAME);
100
}
101
}
102
}
103
// 清除
104
for(i = 0; i < lenum.length; i++)
105
{
106
DelName(lenum.lana[i], SERVER_NAME);
107
CloseHandle(hArray[i]);
108
}
109
GlobalFree(g_Clients);
110
111
printf("主函数结束\n");
112
113
return 0;
114
}
115
116
// 函数:ClientThread
117
// 说明:该线程处理连接会话的NCB 结构,等待进入的数据,会话关闭时,这些数据返回给客户端
118
DWORD WINAPI ClientThread(PVOID lpParam)
119

{
120
PNCB pncb = (PNCB)lpParam;
121
NCB ncb;
122
char szRecvBuff[MAX_BUFFER],
123
szClientName[NCBNAMSZ + 1];
124
DWORD dwBufferLen = MAX_BUFFER,
125
dwRetVal = NRC_GOODRET;
126
// 发送和接收消息,直到会话关闭
127
128
printf("ClientThread函数开始执行\n");
129
130
FormatNetbiosName(pncb->ncb_callname, szClientName);
131
while (1)
132
{
133
dwBufferLen = MAX_BUFFER;
134
dwRetVal = Recv(pncb->ncb_lana_num, pncb->ncb_lsn,
135
szRecvBuff, &dwBufferLen);
136
if (dwRetVal != NRC_GOODRET)
137
break;
138
szRecvBuff[dwBufferLen] = 0;
139
printf("READ [LANA=%d]: '%s'\n", pncb->ncb_lana_num,
140
szRecvBuff);
141
dwRetVal = Send(pncb->ncb_lana_num, pncb->ncb_lsn,
142
szRecvBuff, dwBufferLen);
143
if (dwRetVal != NRC_GOODRET)
144
break;
145
}
146
printf("Client '%s' on LANA %d disconnected\n", szClientName,
147
pncb->ncb_lana_num);
148
//
149
// 如果从读或写返回NRC_SCLOSED 错误,说明没有问题,如果发生其它错误,则在这端挂起
150
// 连接
151
if (dwRetVal != NRC_SCLOSED)
152
{
153
ZeroMemory(&ncb, sizeof(NCB));
154
ncb.ncb_command = NCBHANGUP;
155
ncb.ncb_lsn = pncb->ncb_lsn;
156
ncb.ncb_lana_num = pncb->ncb_lana_num;
157
if (Netbios(&ncb) != NRC_GOODRET)
158
{
159
printf("ERROR: Netbios: NCBHANGUP: %d\n",
160
ncb.ncb_retcode);
161
GlobalFree(pncb);
162
dwRetVal = ncb.ncb_retcode;
163
}
164
165
}
166
// 传递进来NCB 结构是动态分配的空间,要注意删除
167
GlobalFree(pncb);
168
169
printf("ClientThread函数开始结束\n");
170
171
return NRC_GOODRET;
172
}
173
174
//
175
// 函数:Listen
176
// 说明:对每个给定LANA 号异步监听,传递进来的NCB 结构已经将它的ncb_event 域设为有效的
177
// 窗体事件句柄
178
179
int Listen(PNCB pncb, int lana, char *name)
180

{
181
pncb->ncb_command = NCBLISTEN | ASYNCH;
182
pncb->ncb_lana_num = lana;
183
//
184
// 客户端要连接的名字
185
printf("Listen函数开始执行\n");
186
//
187
memset(pncb->ncb_name, ' ', NCBNAMSZ);
188
strncpy(pncb->ncb_name, name, strlen(name));
189
memset(pncb->ncb_callname, ' ', NCBNAMSZ);
190
pncb->ncb_callname[0] = '*';
191
if (Netbios(pncb) != NRC_GOODRET)
192
{
193
printf("ERROR: Netbios: NCBLISTEN: %d\n", pncb->ncb_retcode);
194
return pncb->ncb_retcode;
195
}
196
197
printf("Listen函数开始结束\n");
198
199
return NRC_GOODRET;
200
}
201
202
/**//*
203
其中,main 函数的首次循环需要遍历每个可用的LANA 编号,为其增加服务器名字,执行NCBLISTEN
204
命令,并同时构建由事件句柄构成的数组。接下来调用WaitForMultipleObjects。在其中一个句柄收
205
到信号之前(即进入传信状态之前),这个调用会一直等待。一旦事件控制数组中的一个或多个句柄
206
进入传信状态,WaitForMultipleObjects 调用便会完毕,代码会构建一个线程,用它读取进入的消息,
207
并将其原封不动回送给客户端。随后,代码会为传信状态的NCB 结构创建一个副本,将其传递进入客
208
户端线程。之所以要这样做,是由于我们希望沿用最初的NCB,以执行另一个NCBLISTEN 监听命令。
209
要达到这个目的,可重设事件,并针对那个结构再次调用Listen。注意此时没有必要将整个结构都复
210
制下来。
211
在实际应用中,只需用到本地会话编号(ncb_lsn)和LANA 编号(ncb_lana_num)就可以了。然
212
而,要想同时容纳两个值,打算将其都传递给同一个线程参数,那么NCB 结构是一个非常不错的容器。
213
事件模型使用的客户端线程与回调模型使用的那个几乎完全相同,只是这里采用了GlobalFree 语句。
214
需要注意的是,对前述的两种服务器工作模式来说,都可能存在拒绝为客户端提供服务的情况。
215
NCBLISTEN 完成后,在调用回调函数之前,或在事件收到信号之前,都存在少许的延时。只有在
216
经历了几个语句之后,服务器才会执行另一个NCBLISTEN 命令。例如,假定服务器在LANA2 上接受了
217
一个客户端的连接。随后,在服务器针对同一个LANA 编号执行另一个NCBLISTEN 之前,假如又有一个
218
客户端试图建立连接,便会收到一个名为NRC_NOCALL (0x14)的错误信息。这意味着,对指定的名字
219
来说,目前尚未在它上面执行NCBLISTEN。要防止此类情况的出现,服务器必须为每个LANA 都执行多
220
个NCBLISTEN 命令。从前述两个服务器应用的例子可以看出,异步命令的执行其实是非常容易的。
221
ASYNCH 标志可应用于几乎所有NetBIOS 命令。只是要记住,传递给NetBIOS 的NCB 结构有一个全局性
222
的范围。
223
*/