您的位置:首页 > 理论基础 > 计算机网络

基于TCP的局域网多用户通信、文件传送程序详解

2007-11-22 17:46 615 查看

一、构架设计
  整个系统分为三个相关的程序模块,即注册登陆服务器(wbQQRegSer)、聊天通信服务器(wbQQChat)以及用户程序(wbQQClient)。其中,注册登陆服务器负责用户的注册、登陆以及数据库管理;通信服务器负责完成数据转发以及共享数据结构的管理;用户端则完成注册、登陆、通信和文件传送功能。在进行文件传送时,任一客户程序均可以既作为文件传送服务器发送文件,也可以作为客户端接收文件,实现半双工的文件传送。整个系统构成如图一:



图一 系统构架图


二、注册登录服务器设计
   注册登录服务器采用面向连接的并发式方式,服务器设计成为一个对话框程序。调用WSAStartup初始化动态库,socket函数创建套接字, bind函数绑定本地IP地址和端口,listen函数使套接字进入侦听,然后由于调用accept()函数将产生阻塞,所以不宜在主线程中调用该函数, 因而在初始化网络后 当用户按下“运行注册登录服务器”按钮后,利用侦听套接字启动注册登录线程RegLoad(void *s)进入无限循环,在线程中调用accept函数,用来接受来自客户端的连接请求,每当一个连接请求到来时,accept()函数将产生一个新的套接 字,利用这个套接字产生一个新的线程talkToClient(void *cs)与客户端进行通信并读写数据库,通信完毕后关闭该套接字和线程,原来的侦听套接字继续处于侦听状态。
  两个服务器程序可以在同一台物理机器上运行,也可以在不同的机子上运行,为方便服务器的控制,在注册登录服务器调用函数

CreateProcess( NULL,
".//..//wbQQChat//wbQQChat.exe", 	// Command line.
NULL,             // Process handle not inheritable.
NULL,             // Thread handle not inheritable.
FALSE,            // Set handle inheritance to FALSE.
0,                // No creation flags.
NULL,             // Use parent''''s environment block.
NULL,             // Use parent''''s starting directory.
&si,              // Pointer to STARTUPINFO structure.
&pi )

创建聊天通信服务器进程,想关闭时则调用TerminateProcess(m_hProcChat, 2)函数关闭此进程。


三、聊天通信服务器设计
  聊天通信服务器设计为无界面的进程(创建时先建一个基于对话框的应用程序,然后把对话框类删除,把APP类里面与对话框有关的语句全删除即可创建无界面进程),采用共享数据结构,为每个客户端创建两个线程,实现接收和转发的功能。第一个线程用于发送,
hHandleSend = AfxBeginThread(SendData,(LPVOID)clientSocket,0,0,CREATE_SUSPENDED,NULL);

第二个线程用于接收:

hHandleRecv = AfxBeginThread(RecvData, (LPVOID)clientSocket);



四、客户端设计
  客户端设计成为对话框的用户界面,主要分成四个模块,分别是注册模块、登录模块、聊天模块和文件传送模块。
   在程序运行后的第一个对话框,客户可以选择登录或注册,若是注册则启动注册向导,分三步完成注册工作,第一步为基本信息登记,包括头像选择、用户名、性 别、密码,其中用户名和密码将在注册成功后登录使用。第二步为详细资料,包括真实姓名、城市、E-mail地址和电话号码。第三步为网络设 置,分别是注册登录服务器的IP地址和端口号,聊天通信服务器的IP地址和端口号,也就是说两个服务器程序可以分别位于不同的物理机器,以减轻服务器运行 时的负荷。点击确定后,客户端将与指定的IP地址和端口号去连接注册登录服务器,成功连接后服务器执行注册操作,并返回注册结果。
  客户注册成功后,即可用注册时的用户名和密码进行登录,将登录信息按注册时的网络设置发往服务器,服务器执行登录操作并返回注册结果,登录成功则连接聊天通信服务器,否则退出程序。
登录成功出现聊天对话框,可以从下拉组合框选择好友,发送信息的同时将信息写入聊天记录文件,服务器收到信息后依照接收者用户名进行转发。若客户收到信息则闪动托盘处的图标,提示用户收到信息,用户可以点击回答进行回复。
   当登录成功后,用户也可以在选择好友后点击传送文件按钮来进行文件传送。当客户A向客户B发送文件时,A弹出传送文件对话框,提示给B发送文件,等待B 的回应,客户B将弹出消息框告知A向B发送文件,B可以接收也可以拒收。文件收发完毕后,点击关闭按钮关闭文件传送对话框。


五、网络传输协议设计
  为了让客户端和服务器能够协同工作,必须在通信过程中定义一套规则也就是协议,让双方能够相互听懂,并依照协议执行相应的功能块。
   客户端注册时发送的消息为Reg: + BasicDlg.m_strUserName + BasicDlg.m_nAge + sex + BasicDlg.m_strPassWd + MiscDlg.m_strTruName + MiscDlg.m_strCity + MiscDlg.m_strEmail + res + MiscDlg.m_strTel,注册时发送消息的头部为Reg。登录时发送的消息为:Load: + m_strUserName + m_strPassWd,登录时发送消息的头部为Load。注册登录服务器收到客房端的消息后检查其头部,若是Reg则执行注册操作,注册成功则返回 success!,用户名已经存在则返回exist!,其它原因注册不成功则返回Error!;若是Load则执行登录操作,登录成功返回 success!,登录不成功则返回error!。客户端依照返回信息做出相应提示,并执行相应功能模块。
  登录成功后,客户端将自己的用户名 发送给聊天通信服务器,服务器为客户端创建一个套接字,两个线程,并填充socketInfo结构,连入链表。客户端发送消息结构为:“接收者用户名” + “:” + “发送者头像ID” + “~” + “(星期、月、日、年、时、分、秒)” +"/t" +"发送者用户名" +“->” + “接收者用户名” +"/n/r" + “发送的消息”,其头部均为接收者用户名,服务器依照用户名查找链表,截掉头部后把原信息进行转发,若客户端关闭, 则发送消息为Close!,服务器从链表中删除相应项。
  客户端可能收到的消息有三种,第一种为普通消息,结构如前所述;第二种为 SendFile!,表示对方想向己方传送文件;第三种为Refuse!,表示对方拒绝接收己方文件。客户端A想给客户端B传送文件,则发送消息为 SendFile!,B收到SendFile!后弹出消息框,提示对方向己方传送文件,接收按“是”,执行文件接收功能;拒绝按“否”,发送 Refuse!


六、附加说明

本软件在win2000professionSP4 + VC6MFC环境下开发和测试通过,使用前要注册ODBC数据源;数据源名称:wbQQuser;类型:ACCESS;文件名:wbQQuser.mdb,不明了之处请参看源程序,注释很清楚。

多线程通信使用的全局变量导致函数耦合度较大。

有些函数太长,导致功能不单一,内聚度降低。

客户端点击传送文件后,应使该按钮无效,直到文件传送完毕或文件传送线程关闭再使之有效,如不使用全局变量有什么好办法实现。

  我认为学好一种技术爱好是最好的老师,交流是最好的方法,请高手赐教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: