作者:袁 渊(华东船舶工业学院机械系) 转载请与作者联系 三、具体实施 3.2 通信服务器 ●多线程 每当服务器上有用户连接成功,服务器都会为其创建两个线程:接收线程(RecvData)和发送线程(SendData),并且接收线程在创建后处于可执行状态,而发送线程则阻塞,等待服务器将其唤醒。这两个线程都执行一个无限循环的过程,只有当通信出现异常或用户端关闭连接时,线程才被自身所结束,并且,这两个线程一定是同时生成,同时结束的。很显然,每个连接产生两个线程,使得数据转发变的简单,但同时又使得服务器的任务加重。因此,用户端的连接数量有所限制,视服务器软、硬件能力而定。 同时,由于多线程对结构体info_data都需要操作,所以线程间必须同步。这儿,我定义了互斥量CMutex m_mutex,用它的方法Lock()和Unlock()来完成同步。 我们首先来看一下接收线程(RecvData):(不完整代码) UINT RecvData(void* cs) { SOCKET clientSocket=(SOCKET)cs; while(1) { numrcv=recv(clientSocket, buffer, MAXBUFLEN, NO_FLAGS_SET); buffer[numrcv]=''/0''; if(strcmp(buffer,"Close!")!=0) //不是接收的“Close”数据 { ………… for(i=0;i<COUNT;I++) { if(po!=NULL) { s1=s_info.GetNext(po); if(s1.pet.Compare(petname)==0) //比较昵称是否一样 { m_mutex.Lock(); //互锁 info_data.data=pos; info_data.thread=s1.thread; m_mutex.Unlock(); //解锁 } s1.thread->ResumeThread(); //恢复发送相应的线程 break; } } } else { ………… if(clientSocket==s1.s_client) { m_mutex.Lock(); //互锁 info_data.data=buffer; m_mutex.Unlock(); //解锁 s1.thread->ResumeThread(); //恢复发送相应的线程 s_info.RemoveAt(po1); //删除该用户信息 break; } ……… goto aa; } } aa: closesocketlink((LPVOID)clientSocket); //关闭连接 AfxEndThread(0,true); //结束本线程 return 1; } 接下来看一下发送线程(SendData):(不完整代码) UINT SendData(void* cs) { SOCKET clientSocket=(SOCKET)cs; while(1) { if(info_data.data!="Close!") { m_mutex.Lock(); //互锁 numsnd=send(clientSocket,info_data.data, info_data.data.GetLength(),NO_FLAGS_SET); //发送数据 now=info_data.thread; m_mutex.Unlock(); //解锁 now->SuspendThread(); //自身挂起 } else { goto bb; } } bb: closesocketlink((LPVOID)clientSocket); //关闭连接 AfxEndThread(0,true); //结束本线程 return 1; } 3.3 用户端 很显然,用户端不用考虑多线程,网络连接技术也比较成熟,因此在通信方面没有什么难题。但是,用户端是面向实际用户的,所以,不论是界面还是功能都必须友好。就像大多数软件的更新一样,界面友好度的提高以及功能的完善往往是放在首位的。由此可见,单从总体设计与技术实现角度来讲,用户端的工作量是十分大的,并且设计较服务器端复杂得 多。我粗略总结了以下几条: ●与服务器通信格式兼容; ●操作简单、易用,有美观的界面及快捷键; ●准确地接收和传输数据; ●所有的数据记录与提取功能; ●多种消息接收提示方式,比如托盘图标(发送者头像)闪烁、声音提示等; 根据以上内容,我设计了三个独立的对话框分别用来完成注册、登陆、通信功能,登陆和注册对话框与服务器的56789I/O端口连接,通信对话框与服务器的56790I/O端口连接,这样就很好地实现了注册登陆与通信的隔离,既能使服务器负载降低,同时又能保证一定的通信安全性。 由于本部分不是主要内容,详细代码见程序。 四、结束语 通过以上阐述可以知道,本系统分为服务器端和用户端,服务器端又分为注册/登陆服务器和通信服务器,通过通信服务器的转发功能实现了局域网内的多用户通信功能。本文运用了多线程技术和共享数据结构技术实现了通信服务器的转发功能,使一般基于TCP/IP的网络应用程序得到了发展。本系统已经在我实验室的局域网(一台服务器,二十台客户机)运行通过。 参考文献: [1] Eugene Olafsen ,Kenn Scribner, K.David White等著. MFC Visual C++ 6.0编程技术内幕. 北京:机械工业出版社 2000.2 [2] Charles Wright. Visual C++程序员实用大全. 北京:中国水利水电出版社 2001.10 作者信息: 袁 渊(华东船舶工业学院 机械系,江苏 镇江 212003) |