C#聊天软件解析.docx
《C#聊天软件解析.docx》由会员分享,可在线阅读,更多相关《C#聊天软件解析.docx(24页珍藏版)》请在冰豆网上搜索。
C#聊天软件解析
C#FREECHAT
聊天程序报告
学院:
信息学院
班级:
计算机113
学号:
1108010305
姓名:
卢庆乐
目录
一.作品设计概述:
3
1.背景意义3
二.作品分析设计3
1.主要功能及分析3
2.层次结构及各层通信协议4
三.作品主要功能使用说明及演示15
四.结论19
五.参考文献20
一.作品设计概述:
1.背景意义
在网络信息技术高速发展的今天,传统的通信方式已然满足不了人们的需求。
利用网络资源实现多机通信可以最大程度地满足人们对通信的需求,而不限制于距离地点。
而如今流行着很多种网络聊天工具,如QQ,MSN等,都是集成的多功能聊天工具。
所以,我利用这学期所学的关于C#的相关知识及网络资源,利用.NET平台实现了一个简单的聊天工具。
具备了和聊天相关的基本功能,而开发这个软件的最大意义我认为在于巩固和加深对C#相关知识的学习。
二.作品分析设计
1.主要功能及分析
(1)进行即时通信
该功能主要指服务器和多个客户端进行即时通信。
该功能实现的主要是文本传输。
而对于发送即时消息的过程中,用户可以自定义设置发送文本的字体大小,清空输入框,保存聊天记录,导出聊天记录等功能。
只要成功与服务器端连接,可以实现多个客户端与服务器进行即时通信。
2.层次结构及各层通信协议
层次结构可以大体分为服务器和客户端两大部分,下面对其进行具体说明:
(1)服务器模块
A.实现框图:
B.主要类设计:
(server的设计)
调用到的主要类及方法属性:
1.线程类:
ThreadStarThread(线程同步)
2.IP地址:
IPAddressIPAddress.Parse()
3.监听:
TcpListenernetStream
4.信息传送(流):
ReadWriteObject
C.附上主要部分程序(利用多线程实现监听和建立通信连接部分)
privatevoidSetServerIPAndPort()
{
FileStreamfs=newFileStream("ServerIPAndPort.txt",FileMode.Open);
StreamReadersr=newStreamReader(fs);
stringIPAndPort=sr.ReadLine();
ServerIP=IPAndPort.Split(':
')[0];//设定IP
port=int.Parse(IPAndPort.Split(':
')[1]);//设定端口
sr.Close();
fs.Close();
}
privatevoidbutton1_Click(objectsender,EventArgse)
{
myListener=newTcpListener(IPAddress.Parse(ServerIP),port);
myListener.Start();
AddItemToListBox(string.Format("开始在{0}:
{1}监听客户连接",ServerIP,port));
//创建一个线程监客户端连接请求
ThreadmyThread=newThread(ListenClientConnect);
myThread.Start();
button1.Enabled=false;
button2.Enabled=true;
}
privatevoidListenClientConnect()
{
TcpClientnewClient=null;
while(true)
{
try
{
newClient=myListener.AcceptTcpClient();
}
catch
{
//当单击‘停止监听’或者退出此窗体时AcceptTcpClient()会产生异常
//因此可以利用此异常退出循环
break;
}
//每接收一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息;
Useruser=newUser(newClient);
ThreadthreadReceive=newThread(ReceiveData);
threadReceive.Start(user);
userList.Add(user);
AddItemToListBox(string.Format("[{0}]进入",newClient.Client.RemoteEndPoint));
AddItemToListBox(string.Format("当前连接用户数:
{0}",userList.Count));
}
}
///
///处理接收的客户端信息
///
///客户端信息
privatevoidReceiveData(objectuserState)
{
Useruser=(User)userState;
TcpClientclient=user.client;
while(isNormalExit==false)
{
stringreceiveString=null;
try
{
//从网络流中读出字符串,此方法会自动判断字符串长度前缀
receiveString=user.br.ReadString();
}
catch(Exception)
{
if(isNormalExit==false)
{
AddItemToListBox(string.Format("与[{0}]失去联系,已终止接收该用户信息",client.Client.RemoteEndPoint));
RemoveUser(user);
}
break;
}
AddItemToListBox(string.Format("来自[{0}]:
{1}",user.client.Client.RemoteEndPoint,receiveString));
string[]splitString=receiveString.Split(',');
switch(splitString[0])
{
case"Login":
user.userName=splitString[1];
SendToAllClient(user,receiveString);
break;
case"Logout":
SendToAllClient(user,receiveString);
RemoveUser(user);
return;
case"Talk":
stringtalkString=receiveString.Substring(splitString[0].Length+splitString[1].Length+2);
AddItemToListBox(string.Format("{0}对{1}说:
{2}",user.userName,splitString[1],talkString));
SendToClient(user,"talk,"+user.userName+","+talkString);
foreach(UsertargetinuserList)
{
if(target.userName==splitString[1]&&user.userName!
=splitString[1])
{
SendToClient(target,"talk,"+user.userName+","+talkString);
break;
}
}
break;
default:
AddItemToListBox("什么意思啊:
"+receiveString);
break;
}
}
}
///
///发送消息给所有客户
///
///指定发给哪个用户
///信息内容
privatevoidSendToAllClient(Useruser,stringmessage)
{
stringcommand=message.Split(',')[0].ToLower();
if(command=="login")
{
//获取所有客户端在线信息到当前登录用户
for(inti=0;i{
SendToClient(user,"login,"+userList[i].userName);
}
//把自己上线,发送给所有客户端
for(inti=0;i{
if(user.userName!
=userList[i].userName)
{
SendToClient(userList[i],"login,"+user.userName);
}
}
}
elseif(command=="logout")
{
for(inti=0;i{
if(userList[i].userName!
=user.userName)
{
SendToClient(userList[i],message);
}
}
}
}
///
///发送message给user
///
///指定发给哪个用户
///信息内容
privatevoidSendToClient(Useruser,stringmessage)
{
try
{
//将字符串写入网络流,此方法会自动附加字符串长度前缀
user.bw.Write(message);
user.bw.Flush();
AddItemToListBox(string.Format("向[{0}]发送:
{1}",user.userName,message));
}
catch
{
AddItemToListBox(string.Format("向[{0}]发送信息失败",user.userName));
}
}
///
///移除用户
///
///指定要移除的用户
privatevoidRemoveUser(Useruser)
{
userList.Remove(user);
user.Close();
AddItemToListBox(string.Format("当前连接用户数:
{0}",userList.Count));
}
privatedelegatevoidAddItemToListBoxDelegate(stringstr);
///
///在ListBox中追加状态信息
///
///要追加的信息
privatevoidAddItemToListBox(stringstr)
{
if(listBox1.InvokeRequired)
{
AddItemToListBoxDelegated=AddItemToListBox;
listBox1.Invoke(d,str);
}
else
{
listBox1.Items.Add(str);
listBox1.SelectedIndex=listBox1.Items.Count-1;
listBox1.ClearSelected();
}
}
privatevoidbutton2_Click(objectsender,EventArgse)
{
AddItemToListBox("开始停止服务,并依次使用户退出!
");
isNormalExit=true;
for(inti=userList.Count-1;i>=0;i--)
{
RemoveUser(userList[i]);
}
//通过停止监听让myListener.AcceptTcpClient()产生异常退出监听线程
myListener.Stop();
button1.Enabled=true;
button2.Enabled=false;
}
(2)客户端模块
A.实现框图:
B.主要类设计:
(client类)
调用的主要类及方法成员:
1.启动连接:
TcpClient
2.IP地址:
IPAddressIPAddress.Parse()
3.监听:
TcpListenernetStream
4.信息传送(流):
ReadWriteObject
5.委托:
AsyncCallback
C.附上主要部分程序(利用多线程实现监听和建立通信连接部分)
privatevoidSetServerIPAndPort()
{
try
{
FileStreamfs=newFileStream("ServerIPAndPort.txt",FileMode.Open);
StreamReadersr=newStreamReader(fs);
stringIPAndPort=sr.ReadLine();
ServerIP=IPAndPort.Split(':
')[0];//设定IP
port=int.Parse(IPAndPort.Split(':
')[1]);//设定端口
sr.Close();
fs.Close();
}
catch(Exceptionex)
{
MessageBox.Show("配置IP与端口失败,错误原因:
"+ex.Message);
Application.Exit();
}
}
privatevoidReceiveData()
{
stringreceiveString=null;
while(isExit==false)
{
try
{
//从网络流中读出字符串
//此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
receiveString=br.ReadString();
}
catch
{
if(isExit==false)
{
MessageBox.Show("与服务器失去连接");
}
break;
}
string[]splitString=receiveString.Split(',');
stringcommand=splitString[0].ToLower();
switch(command)
{
case"login":
//格式:
login,用户名
AddOnline(splitString[1]);
break;
case"logout":
//格式:
logout,用户名
RemoveUserName(splitString[1]);
break;
case"talk":
//格式:
talk,用户名,对话信息
AddTalkMessage(splitString[1]+":
\r\n");
AddTalkMessage(receiveString.Substring(splitString[0].Length+splitString[1].Length+2));
break;
default:
AddTalkMessage("什么意思啊:
"+receiveString);
break;
}
}
Application.Exit();
}
///
///向服务端发送消息
///
///
privatevoidSendMessage(stringmessage)
{
try
{
//将字符串写入网络流,此方法会自动附加字符串长度前缀
bw.Write(message);
bw.Flush();
}
catch
{
AddTalkMessage("发送失败");
}
}
privatedelegatevoidAddTalkMessageDelegate(stringmessage);
///
///在聊天对话框(txt_Message)中追加聊天信息
///
///
privatevoidAddTalkMessage(stringmessage)
{
if(txt_Message.InvokeRequired)
{
AddTalkMessageDelegated=newAddTalkMessageDelegate(AddTalkMessage);
txt_Message.Invoke(d,newobject[]{message});
}
else
{
txt_Message.AppendText(message+Environment.NewLine);
txt_Message.ScrollToCaret();
}
}
privatedelegatevoidAddOnlineDelegate(stringmessage);
///
///在在线框(lst_Online)中添加其他客户端信息
///
///
privatevoidAddOnline(stringuserName)
{
if(lst_OnlineUser.InvokeRequired)
{
AddOnlineDelegated=newAddOnlineDelegate(AddOnline);
lst_OnlineUser.Invoke(d,newobject[]{userName});
}
else
{
lst_OnlineUser.Items.Add(userName);
lst_OnlineUser.SelectedIndex=lst_OnlineUser.Items.Count-1;
lst_OnlineUser.ClearSelected();
}
}
privatedelegatevoidRemoveUserNameDelegate(stringuserName);
///
///在在线框(lst_Online)中移除不在线的客户端信息
///
///
privatevoidRemoveUserName(stringuserName)
{
if(lst_OnlineUser.InvokeRequired)
{
RemoveUserNameDelegated=newRemoveUserNameDelegate(RemoveUserName);
lst_OnlineUser.Invoke(d,userName);
}
else
{
lst_OnlineUser.Items.Remove(userName);
lst_OnlineUser.SelectedIndex=lst_OnlineUser.Items.Count-1;
lst_OnlineUser.ClearSelected();
}
}
privatevoidbtn_Send_Click(objectsender,EventArgse)
{
if(lst_OnlineUser.SelectedIndex!
=-1)
{
SendMessage("Talk,"+lst_OnlineUser.SelectedItem+","+txt_SendText.Text+"\r\n");
txt_SendText.Clear();
}
else
{
MessageBox.Show("请先在【当前在线】中选择一个对话着");
}
}
privatevoidtxt_SendText_KeyPress(objectsender,KeyPressEventArgse)
{
if(e.KeyChar==(char)Keys.Return)
{
//触发【发送】按钮的单击事件
btn_Send.PerformClick();
}
}
privatevoidbtn_Login_Click(objectsender,EventArgse)
{
btn_Login.Enabled=false;
try
{
//此处为方便演示,实际使用时要将Dns.GetHostName()改为服务器域名
//IPAddressipAd=IPAddress.Parse("182.150.193.7");
client=newTcpClient();
client.Connect(IPAddress.Parse(ServerIP),port);
AddTalkMessage("连接成功");
}
catch(Exceptionex)
{
AddTalkMessage("连接失败,原因:
"+ex.Message);
btn_Login.Enabled=true;
return;