仿QQ聊天软件基于局域网TCP蓝精灵聊天软件的实现.docx
《仿QQ聊天软件基于局域网TCP蓝精灵聊天软件的实现.docx》由会员分享,可在线阅读,更多相关《仿QQ聊天软件基于局域网TCP蓝精灵聊天软件的实现.docx(61页珍藏版)》请在冰点文库上搜索。
仿QQ聊天软件基于局域网TCP蓝精灵聊天软件的实现
西南大学
计算机与信息科学学院
学年设计报告
课程:
学年设计
题目:
蓝精灵聊天软件
级、专业:
2014级计算机科学与技术专业2班
学生姓名:
杨XX
提交日期:
2016年12月16日
内容提要:
本次的学年设计课题是基于局域网TCP/IP网络通信的聊天软件的实现。
从一定程度上,借鉴了一些其他强大聊天软件的设计开发的基于局域网的聊天软件。
本课题设计主要用的知识涉及到计算机网络、数据库编程、C#网络通信编程等等。
主要的知识点有:
socket套接字、TCP面向连接的网络通信、ISO模型、C/S模型、SQLServer等等。
蓝精灵聊天软件实现了在一个局域网内部的客户端之间通过服务器端进行聊天通信功能。
也就是说,主要包括两个部分的功能,一个是服务器,一个是客户端。
服务器实现了启动监听、响应客户端发来的连接请求、转发从一个客服端接收的消息到另外一个客户端、响应客户端发来的动作请求、关闭监听。
客户端实现了用户注册、用户登录、查找并添加好友、删除好友、好友聊天的功能。
关键词:
SocketTCPClient计算机网络ServerSQLServer
网络通信C#编程C/S模式ISO模型局域网
参考书目:
C#网络通信程序设计精讲吴晨陈建孝编著清华大学出版社
C#开发宝典王小科李继业等编著机械工业出版社
萨师煊数据库系统概论高等教育出版社
计算机网络原书第6版JamesF.KrouseKeithW.Ross机械工业出版社
成绩评定:
指导教师(签字):
年月日
目录
1概述1
2基本概念和方法、工具1
(1)基本概念1
(2)方法2
(3)开发工具3
3设计方案3
(1)总体设计3
(2)界面设计4
(3)服务器端设计说明5
(4)服务器端设计5
(5)客户端设计6
(6)数据库设计9
4源代码10
(1)服务器端10
(2)客户端22
(3)数据库34
5简要的使用说明35
6总结40
7参考文献41
蓝精灵聊天软件系统
1概述
即时通信软件为我们提供了诸多的方便,使我们逐步享受信息时代的便捷。
我们最熟悉的即时通信软件就是QQ了,因为它几乎已经融入了我们每个人的日常生活。
由此可见,生活在信息时代的人们对即时通信、聊天软件有巨大的需求,这样的软件也将为我们节省大量的时间。
然而,基于internet的QQ已经深入人心,要想再去做可能没有任何竞争力。
此时,我们可以换一个角度,调整用户对象。
如今的时代背景下,信息的泄露早已屡见不鲜,尤其是一些大企业的内部信息,如果这些信息泄露,可能会造成巨大的经济损失,甚至将导致企业破产。
因此,为了便捷内部人员之间的交流,做这样的一个内部即时通信、聊天软件还是很有市场的。
我们的目标就是做的仿QQ的聊天软件蓝精灵,面向内部人员使用的即时通信软件。
为了方便内部人员之间便捷的交流,需要开发一款适合内部人员进行即时通信的软件,这样的软件既满足了内部人员之间便捷的交流,同时,也防止内部信息的外流,开发这样一款即时通信软件,是很有必要的。
综合以上因素,我们利用C#网络通信编程实现了基于TCP/IP可靠网络通信系统—蓝精灵聊天软件。
本软件包括两个部分,客户端和服务器。
服务器的功能主要是监听客户端发来的连接请求并予以响应、转发客户端的信息、响应客户端执行注册、登录等的操作以及关闭连接。
客户端主要是界面,注册、登录、搜索添加好友、删除好友以及与好友聊天的功能实现。
2基本概念和方法、工具
(1)基本概念
TCP:
是一种面向连接的、可靠的、基于字节流的传输层通信协议。
套接字:
IP地址和目的IP地址以及源端口号和目的端口号的组合,其用于标识客户端请求的服务器和服务。
C/S模式:
C/S结构,客户机和服务器结构。
局域网:
在一个局部的地理范围内(如一个学校、工厂和机关内),将各种计算机、外部设备和数据库等互相联接起来组成的计算机通信网,简称LAN。
它可以通过数据通信网或专用数据电路,与远方的局域网、数据库或处理中心相连接,构成一个大范围的信息处理系统。
套接字简介:
套接字最早是Unix的,window是借鉴过来的。
TCP/IP协议族提供三种套接字:
流式、数据报式、原始套接字。
其中原始套接字允许对底层协议直接访问,一般用于检验新协议或者新设备问题,很少使用。
套接字编程原理:
延续文件作用思想,打开‐读写‐关闭的模式
(2)方法
采用Socket异步通信方式
服务器端:
a.主界面:
privatevoidbtnStart_Click(objectsender,EventArgse);/*点击启动按钮的响应函数*/
privatevoidAcceptCallback(IAsyncResultar);/*异步接收来自客户端的消息*/
privatevoidReceiveCallback(IAsyncResultar);/*对接收到的消息进行处理*/
privatevoidRespond(MyFriendfrd,ClassMessagemsg);/*服务器对客户端消息的响应函数*/
privatevoidSendData(MyFriendfrd,ClassMessagemsg);/*发送反馈消息给当前客户端*/
privatevoidSendDataTo(MyFriendfrd,ClassMessagemsg);/*发送聊天信息给在线客户端*/
privatevoidbtnStop_Click(objectsender,EventArgse);/*点击结束按钮的响应函数*/
b.Data控件:
publicintLoginExSQL(LoginMsgmsg,stringremoteEndPoint);/*查询数据库验证登录信息*/
publicintRegistExSQL(ClassMessagemsg);/*在数据库插入注册用户信息并返回注册结果*/
publicClassMessageGetmymsgExSQL(ClassMessagemsg);/*从数据库中获取用户信息*/
publicstring[]GetfriendsExSQL(ClassMessagemsg,outintcount);/*获取好友ID*/
publicSqlDataReaderGetfriMsgExSQL(stringFriendMsg,intflag);/*从数据库中获取用户的好友信息*/
publicintAddFrinedExSQL(ClassMessagemsg);/*将好友相关信息插入数据库Friends表*/
publicintDeleteExSQL(ClassMessagemsg);/*从Friends表中删除好友相关信息*/
客户端:
a.登录界面:
privatevoidbutton_register_Click(objectsender,EventArgse);/*注册按钮的点击响应*/
privatevoidbutton_Login_Click(objectsender,EventArgse)/*登录按钮的点击响应*/
privatevoidLogin_OK()/*登录成功,进入好友列表界面函数*/
privatevoidbutton_Quit_Click(objectsender,EventArgse)/*退出按钮的点击响应*/
b.注册界面:
privatevoidbutton_register_Click(objectsender,EventArgse)/*立即注册按钮的点击响应*/
privatevoidbutton_Cancel_Click(objectsender,EventArgse)/*取消按钮的点击响应*/
c.好友列表界面:
privatevoidFriendList_Load(objectsender,EventArgse)/*好友列表界面主窗体显示*/
privatevoidShowMymsg()/*用户信息初始化及显示*/
privatevoidAddFriends(TCPSocketclient,ClassMessagemsg)/*显示好友列表信息*/
privatevoidbutton_Search_Click(objectsender,EventArgse)/*搜索按钮的点击响应*/
privatevoidStartChat()/*进入聊天界面函数*/
privatevoidItemDoubleClick(objectsender,MouseEventArgse)/*双击好友项的响应函数*/
privatevoid删除好友ToolStripMenuItem_Click(objectsender,EventArgse)/*右键菜单选项删除好友点击响应*/
privatevoid发起会话ToolStripMenuItem_Click(objectsender,EventArgse)/*右键菜单选项发起会话点击响应*/
d.搜索好友界面:
publicSearchFriends(TextBoxtextBox_Search,Labellabel_userName)/*有参构造函数*/
privatevoidSearchFriends_Load(objectsender,EventArgse)/*搜索界面主窗体显示*/
privatevoidRespondSearch(ClassMessagemsg)/*搜索结果处理*/
privatevoidpb_SFhead_Click(objectsender,EventArgse)/*头像图片框点击响应函数*/
privatevoidbtSearch_Click(objectsender,EventArgse)/*搜索按钮的点击响应*/
e.好友聊天界面:
publicChat(ListViewItemlistViewItem,stringUserName)/*有参构造函数*/
privatevoidChat_Load(objectsender,EventArgse)/*聊天界面主窗体显示*/
privatevoidRun()/*获取聊天消息进程*/
privatevoidbutton_Close_Click(objectsender,EventArgse)/*关闭按钮的点击响应*/
privatevoidbutton_Send_Click(objectsender,EventArgse)/*发送按钮的点击响应*/
privatevoidGetBSmsg(ClassMessagemsg)/*聊天消息的处理及显示*/
f.TCPSocket控件:
publicvoidConnection()/*连接服务器端*/
publicClassMessageSendReceive(ClassMessagemsg)/*发送信息并接收响应
publicvoidSendMsg(ClassMessagemsg)/*发送信息*/
publicClassMessageReceiveMsg()/*接收信息*/
publicvoidShutSocket()/*关闭远程连接并释放资源*/
(3)开发工具
VisualStudioC#
SQLServer
3设计方案
(1)总体设计
程序设计:
服务器客户端信息交互设计:
(2)界面设计
(3)客户端详细功能结构设计:
(4)服务器端设计说明:
服务器端主界面,如下所示,为服务器端界面设计的截图,界面主要包括三个部分,分别实现的是显示服务器进行的响应操作、显示服务器响应客户端主机的套接字以及启动监听和关闭监听。
当用鼠标单击“启动”是,服务器开始工作,监听。
此时若有用户加入到服务器,右边的框将会显示加入用户的IP地址,若是发生了数据交换。
左边的框图将会显示交换动态。
(5)客户端设计说明:
客户端的界面设计较服务器稍微复杂,主要包括注册界面、登录界面、登陆之后的主界面、好友搜索界面以及与好友聊天的界面,以下分别介绍。
a.登录界面:
登录界面主要实现两个功能。
一个是用户登录。
一个是当用户还没有注册时,需要注册时,即可点击注册跳转到注册界面。
b.注册界面:
注册界面需要填写的信息包括姓名、密码、性别以及年龄,以此作为用户的基本信息,其中账户密码是用户登录的依据。
通过注册成功的用户,其信息将会被插入到数据表UserInfo中。
c.好友列表界面:
登录界面中点击登录之后跳转到的界面。
好友界面显示的信息有用户头像、用户昵称、用户在线状态、搜索好友文本框和按钮以及我的好友列表。
在此界面中单击好友项,鼠标右键,可以弹出两个选项:
删除好友和发起会话,点击可实现相应功能。
d.搜索好友界面:
在主界面中的搜索框内输入要搜索的好友名,点击搜索按钮,就可直接跳转到好友搜索的界面,并在界面显示出搜索的结果。
若想直接添加为好友,直接单击好友头像即可添加并返回好友列表界面(此时已加入新好友)。
若是想另外搜索好友,可在搜索文本框里输入要搜索的好友名,单击搜索即可。
e.好友聊天界面:
进入好友聊天界面,直接在下面的文本框内输入想要与好友发送的内容,点击发送即可将消息发送给对方,要求双方同时在线聊天。
(6)数据库设计
本程序示通过用ADO来访问数据库,分别用ADO访问了数据库的各个对象及各方法。
数据库主要包括两个表:
一个用来存储好友信息;一个用来存储用户信息。
数据库还要根据客户端的操作及时更新表的内容。
表UserInfo:
用来存储已注册用户的帐号信息。
主要包括昵称、密码、头像、性别、年龄等信息的。
表Friends:
用来存储我的好友信息。
Friends和UserInfo表的关系:
4源代码
(1)服务器端
a.主界面:
//点击启动按钮的响应函数
privatevoidbtnStart_Click(objectsender,EventArgse)
{
//Startlistening
if(IsStart)return;
IPAddressip=IPAddress.Any;//提供一个IP地址,指示服务器应侦听所有网络接口上的客户端活动
IPEndPointlocalep=newIPEndPoint(Dns.Resolve(Dns.GetHostName()).AddressList[0],11000);
listener=newTcpListener(localep);
listener.Start(10);
IsStart=true;
lstBox1.Invoke(AppendString,string.Format("服务器启动侦听!
端点为:
{0}",listener.LocalEndpoint.ToString()));
ClientSocket=newSocket[256];
//接受连接请求的异步调用
AsyncCallbackcallback=newAsyncCallback(AcceptCallback);
listener.BeginAcceptSocket(callback,listener);
btnStart.Enabled=false;
}
//异步接收来自客户端的消息
privatevoidAcceptCallback(IAsyncResultar)
{
try
{
//完成异步接受连接的请求的异步调用
//将接收信息添加到列表中
Sockethandle=listener.EndAcceptSocket(ar);
MyFriendfrd=newMyFriend(handle);
//保存为此客户建立的连接
ClientSocket[ClientNum++]=handle;
lstBoxStatu.Invoke(Addfriend,frd);
AsyncCallbackcallback;
//继续调用异步方法接受连接请求
if(IsStart)
{
callback=newAsyncCallback(AcceptCallback);
listener.BeginAcceptSocket(callback,listener);
}
//开始在异步连接上进行异步的数据接收
frd.ClearBuffer();
callback=newAsyncCallback(ReceiveCallback);
frd.socket.BeginReceive(frd.Rcvbuffer,0,frd.Rcvbuffer.Length,SocketFlags.None,callback,frd);
}
catch
{
IsStart=false;
}
}
//对接收到的消息进行处理
privatevoidReceiveCallback(IAsyncResultar)
{
MyFriendfrd=(MyFriend)ar.AsyncState;
try
{
inti=frd.socket.EndReceive(ar);
if(i==0)
{
lstBoxStatu.Invoke(Removefriend,frd);
return;
}
else
{
ClassMessagemsg=newClassMessage();
msg=(ClassMessage)newClassSerializers().DeSerializeBinary(newMemoryStream(frd.Rcvbuffer));
stringdata=string.Format("Form:
{0}",frd.socket.RemoteEndPoint.ToString());
lstBoxStatu.Invoke(AppendString,data);
//响应客户端请求
Respond(frd,msg);
frd.ClearBuffer();
AsyncCallbackcallback=newAsyncCallback(ReceiveCallback);
frd.socket.BeginReceive(frd.Rcvbuffer,0,frd.Rcvbuffer.Length,SocketFlags.None,callback,frd);
}
}
catch
{
lstBoxStatu.Invoke(Removefriend,frd);
}
}
//服务器对客户端消息的响应函数
privatevoidRespond(MyFriendfrd,ClassMessagemsg)
{
//根据接收信息给出响应
switch(msg.msgCommand)
{
caseMsgCommand.Logining:
DataLoginSQL=newData();
LoginMsglog_msg=(LoginMsg)newClassSerializers().DeSerializeBinary(newMemoryStream(msg.Data));
if(LoginSQL.LoginExSQL(log_msg,frd.socket.RemoteEndPoint.ToString())==1)
{
msg.msgCommand=MsgCommand.Logined;
}
SendData(frd,msg);
break;
caseMsgCommand.Registering:
DataRegistSQL=newData();
if(RegistSQL.RegistExSQL(msg)==1)
{
msg.msgCommand=MsgCommand.Registered;
}
SendData(frd,msg);
break;
caseMsgCommand.Mymsggeting:
DataMymsgSQL=newData();
//获取并发送用户信息
ClassMessagemsgG=MymsgSQL.GetmymsgExSQL(msg);
msgG.msgCommand=MsgCommand.Mymsggot;
SendData(frd,msgG);
break;
caseMsgCommand.FriendList:
DataFriListSQL=newData();
intcount=0;
SqlDataReadersdr;
FriendMsgfrimsg=newFriendMsg();
string[]FriendID=FriListSQL.GetfriendsExSQL(msg,outcount);
for(inti=0;i{
sdr=FriListSQL.GetfriMsgExSQL(FriendID[i],0);
sdr.Read();
if(sdr[0]!
=DBNull.Value)
frimsg.Face=(byte[])sdr[0];
elsefrimsg.Face=null;
frimsg.UserName=sdr[1].ToString();
//发送好友信息给客户端
msg.Data=newClassSerializers().SerializeBinary(frimsg).ToArray();
msg.msgCommand=MsgCommand.FriendList;
//获取验证消息
SendData(frd,msg);
}
//通知客户端好友信息已查询完
msg=newClassMessage();
SendData(frd,msg);
break;
caseMsgCommand.Frimsggeting:
DataFriMsgSQL=newData();
//获取好友信息并发送
SqlDataReadersdr1=FriMsgSQL.GetfriMsgExSQL(msg.UserName,1);
if(sdr1.Read())
{
if(sdr1[0]!
=DBNull.Value)
msg.Face=(byte[])sdr1[0];
elsemsg.Face=null;
msg.msgCommand=MsgCommand.Frimsggot;
}
SendData(frd,msg);
break;
caseMsgCommand.UpdateState:
DataAddFriSQl=newData();
intstate=AddFriSQl.AddFrinedExSQL(msg);
if(state==1)
{
msg