局域网聊天系统
各种同步、互斥和临界区等操作。Visual C++ 6.0中,使用MFC类库也实现了多线程的程序设计,使得多线程编程更加方便。 3.3.2 Win32 API对多线程编程的支持
Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。下面将选取其中的一些重要函数进行说明。
(1) HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄。
(2) DWORD SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。 (3) DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态,执行线程。 (4) VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
(5) BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用TerminateThread强行终止某一线程的执行。
使用TerminateThread()终止某个线程的执行是不安全的,可能会引起系统不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源。因此,一般不建议使用该函数。
(6)BOOL PostThreadMessage(DWORD wParam,LPARAM lParam);
12
idThread,UINT Msg,WPARAM
该函数将一条消息放入到指定线程的消息队列中,并且不等到消息被该线程
局域网聊天系统
处理时便返回。
调用该函数时,如果即将接收消息的线程没有创建消息循环,则该函数执行失败。
4 总体设计
4.1体系结构设计
通常的通信工具,都采用客户机/服务器(C/S)体系结构,C/S结构是这样的一种结构:它包括一个客户机(或前端),一个服务器(或称后端),客户机的作用是访问和处理远程服务器上的数据,服务器的作用是接收和处理客户机的数据请求。有时,可能有多个客户向同一个服务器同时请求服务,这就需要服务器决定怎样处理这些请求。Client/Server结构是当前数据库应用程序中极为流行的一种方式。尤其是网络技术的发展,使得当前很多系统都采用这种方式进行构造,其最大的优点是将计算机工作任务分别由客户端和服务器端来共同完成,这样有利于充分合理的利用系统资源。另外它的服务器端还可以将信息集中起来,任何客户机都可以通过访问服务器而获得所需的信息。Client/Server模型最终可归结为一种“请求/应答”关系。一个请求总是首先被客户发出,然后服务器总是被动地接收请求,返回客户需要的结果。在客户发出一个请求之前,服务进程一直处于休眠状态。一个客户提出请求后,服务进程被“唤醒”并且为客户提供服务,对客户的请求做出所需要的应答。如下图所示:
图4-1客户机/服务器通信结构示图
13
局域网聊天系统
在客户端启动后,客户端计算得到本地网络的广播地址,进行广播查找服务器端,服务器接收到客户端的广播信息后返回服务器地址,则客户端接收、验证信息并记录服务器端地址,然后客户端启动定时期,定时发送信息到服务器,以告知服务器自己在线,然后服务器返回在线用户列表,服务器依靠客户端发送的信息来更新维护在线用户列表。在客户端与服务器尽心数据交换,拥有了在线用户列表后,就可以选择IP进行客户端之间的点对点信息交流了。如果服务器不在线,则客户端会提示用户退出,在一定的时间后自动退出。
4.2 功能模块划分
根据以上的系统需求分析,以及体系结构设计,可以对系统进行如下的功能模块划分如下图所示。
图4-2 功能模块图
其中主线程模块完成对网络的初始化,然后启动两个子线程:服务端监听线程以及网络扫描模块线程,然后由网络扫描模块得到当前的网络用户分布情况,并填充相关的数据结构,然后生成用户列表界面显示给用户。
通信模块又包括两个子模块:数据接收模块和数据发送模块,这两个模块都由系统定义的网络事件来触发。
输入/输出模块用来响应用户双击用户列表的某一项要准备发送信息时的消息,以及当系统接收到某个网络用户发送来的消息,要将其显示给用户的时候。
网络扫描模块是由主线程模块启动,进行网络扫描,确定哪些用户当前处于可到达状态,以及哪些可到达状态的用户安装有相应的通信软件,并启动之可以与之进行通信。
14
局域网聊天系统
4.3 数据结构设计
(1)在线用户信息结构体: struct USERINFO {
CString ip; BOOL on_line; 链表中删除
USERINFO *next; };
//存储IP
//用于判断次IP是否更新过,未更新则从单向//下一个存储单元的地址,最后一个为NULL
注:用于构建服务器端的在线用户单向链表。
(2)从服务器端发送到客户端的在线用户列表信息结构: (3)传输到线程的信息结构体:
客户端:
struct RECVPARAM {
SOCKET sock; //存储接口套接字 HWND hwnd; //存储窗口句柄 };
服务器端:
struct RECVPARAM {
SOCKET sock; //存储接口套接字 HWND hwnd; //存储窗口句柄
BOOL endtread; //存储用于判断是否退出线程循环 USERINFO *userhead; //存储在线用户单向链表的头指针 };
注:线程函数为静态函数,无法调用成员变量和成员函数,所以需要将需要的数据传送进去。
4.4 用户界面设计
在能够完全满足软件所需功能,设计界面要清爽、操作要简单易懂的基本原则下,本软件的界面设计如下: 4.4.1 服务器端显示界面:
15
局域网聊天系统
图4-3服务器端界面图
4.4.2 客户端显示界面:
图4-4 客户端显示界面
5 详细设计及编码实现
5.1 主框架及用户界面模块详细设计
16