C# 聊天软件.docx
- 文档编号:9242618
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:33
- 大小:99.65KB
C# 聊天软件.docx
《C# 聊天软件.docx》由会员分享,可在线阅读,更多相关《C# 聊天软件.docx(33页珍藏版)》请在冰点文库上搜索。
C#聊天软件
C#专业实践
专业:
软件工程
班级:
0801
学号:
200812052
姓名:
丁志均,邢皓,魏子龙
成绩:
二〇一一年九月
目录
1需求分析-3-
1.1开发背景-3-
1.2功能需求-3-
1.3软件结构-3-
1.3.1服务器端的设计-3-
1.3.2客户端设计-4-
2相关知识-5-
2.1TCP与Socket-5-
3详细设计-7-
3.1服务器端的实现-7-
3.2客户端的实现-18-
4设计总结-25-
1需求分析
1.1开发背景
为了满足学习研究需要,设计本在线C#聊天工具,它提供了基本的聊天功能。
1.2功能需求
①能查看所有在线用户
②能对所有在线用户进行群聊
③支持点对点的单聊
1.3软件结构
本程序包括两个大的方面,服务器端和客户端。
1.3.1服务器端的设计
服务器端管理着聊天任务,维持着一张当前在线用户的列表,转发用户送来的信息。
1)监听本机IP地址的一个指定的端口
2)根据客户端发送来的各种不同的请求,执行相应的操作,并将处理结果返回给该客户端。
3)服务器能够识别6种请求命令:
1CONNECT—连接聊天室
2JOIN—通知本人已加入聊天室
3LIST—抢客户端发送全部登陆用户名
4CHAT—群聊功能
5PRIV—私聊功能
6EXIT|QUIT—退出聊天室
1-1服务器端界面
1.3.2客户端设计
客户端应用程序包括用户登录窗口和用户聊天的主窗口,它允许用户登录到服务器,可以向服务器发送信息,同时可以接收从服务器返回的信息
1)向远程服务器发送连接请求
2)得到服务器程序的确认后,建立与服务器的连接,并获得与服务器交互的流通道
3)通过网络流通道与服务器端的程序进行数据通信。
向服务器发送服务器能够识别的四种指令请求,同时也接收服务器发回的命令。
客户端能够识别的命令有通知当前在线用户有新的用户进入聊天室,更新当前在线用户和关闭客户端程序。
1-2客户端界面
2相关知识
2.1TCP与Socket
1主要包括服务器端的实现和客户端的实现
采用TCP协议通信和Socket编程基础
TCP协议是面向连接的协议,它的实现需要数据发送方和数据接收方建立数据通信连接
具体流程如下:
4)服务器端首先创建服务器套接字
5)服务器套接字监听一个端口,等待客户端的请求
6)客户端创建一个客户端套接字
7)客户端向服务器发送连接请求
8)服务器确认与客户端的连接
9)客户端和服务器利用建立的连接进行通信
10)通信完毕后,客户端和服务器关闭各自的连接
2.Socket编程基础
利用Socket建立一个TCP服务器程序
1)创建一个服务器套接字,用IP地址和端口初始化服务器
2)监听服务器端口
3)确认与客户端的连接
4)处理客户端的请求并回应客户端
5)关闭服务器,释放服务器连接
利用Socket建立客户端程序
1)创建客户端套接字
2)连接服务器
3)得到与服务器通信的流通道
4)向服务器发送数据
5)接收从服务器发回的数据
6)断开连接
2-1服务器与客户端的通信流程
3详细设计
3.1服务器端的实现
为了使用Socke对象和Thread对象,在代码中加入名字空间Systen.Net、System.Net.Sockets和System.Thread的引用
在服务器端使用了多线程,每个用户通过处理一个单独的线程进行连接,当聊天服务器开始运行时,它就启动一个线程等待客户连接。
当接收到一个请求时,服务器立刻启动一个线程来处理和该客户端的信息交互。
这里自定义一个Client类,它用于保存每个当前在线用户的用户名和服务器连接的Socket对象。
当Socket连接一旦建立,就马上将其保存在一个Client对象中,以便让每个用户有自己的Socket,以后可以对不同用户的Socket对象进行操作,实现与客户端的数据交互。
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Collections;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Net;
usingSystem.Net.Sockets;//引入Socket的命名空间
usingSystem.Threading;//引入线程的命名空间
namespaceChatApplicationServer
{
publicpartialclassfrmServerMain:
Form
{
//clients数组保存当前在线用户的client对象
internalstaticHashtableclients=newHashtable();
//该服务器默认的监听器
privateTcpListenerlistener;
//默认最大支持的客户端连接数
staticintMAXUSER=100;
//服务器是否开启的标志
internalstaticboolServerFlag=false;
publicfrmServerMain()
{
InitializeComponent();
}
publicdelegatevoidAppendMsgEventHandler(RichTextBoxrb,stringmsg);//定义在线程中操作不同线程创建的控件的委托
publicdelegatevoidAppendUserEventHandler(ListBoxlb,stringusername);
//开启服务器
privatevoidbtStartServer_Click(objectsender,EventArgse)
{
intiPort=this.returnValidPort(tbServerPort.Text.Trim());
if(iPort<0)
{
MessageBox.Show("错误的端口信息!
","错误提示");
return;
}
stringip=this.returnIpAddress();
try
{
IPAddressuserIP=IPAddress.Parse(ip);
//创建服务器套接字
listener=newTcpListener(userIP,iPort);
listener.Start();
this.rbChatContent.AppendText("服务器已经启动,正在监听"+ip+"端口号:
"+tbServerPort.Text+"..........\n");
frmServerMain.ServerFlag=true;
//以下方法启动一个新的线程,执行监听方法
//以便在一个独立的进程中执行确认与客户端连接的操作
Threadthread=newThread(StartListen);
thread.Start();
btStartServer.Enabled=false;
btStopServer.Enabled=true;
}
catch(Exceptionex)
{
this.rbChatContent.AppendText(ex.Message+"\n");
}
}
//用于接收客户端的请求,确认与客户端的连接
//并且启动一个新的线程处理客户端的请求
privatevoidStartListen()
{
while(frmServerMain.ServerFlag)
{
try
{
//当接收到客户端请求时,确认与客户端的连接
if(listener.Pending())
{
SocketnewSocket=listener.AcceptSocket();
if(clients.Count>=MAXUSER)
{
MessageBox.Show("连接数已经超过允许连接的最大数"+MAXUSER.ToString()+",拒绝新的连接!
","错误提示");
this.rbChatContent.AppendText("连接数已经超过允许连接的最大数"+MAXUSER.ToString()+",拒绝新的连接!
");
newSocket.Close();
}
else
{
//启动一个新的线程,处理用户相应的请求
ChatClientnewClient=newChatClient(this,newSocket);
ThreadClientThread=newThread(newClient.ClientService);
ClientThread.Start();
}
}
Thread.Sleep(50);
}
catch(Exceptionex)
{
this.UpdateMsg(ex.Message);
}
}
}
//获取有效的端口号
privateintreturnValidPort(stringstrPort)
{
intport;
//测试端口号是否有效
try
{
if(tbServerPort.Text=="")
{
thrownewArgumentException("端口号为空,不能启动服务器!
");
}
else
{
port=Convert.ToInt32(tbServerPort.Text.Trim());
}
}
catch(Exceptionex)
{
this.rbChatContent.AppendText("无效的端口号:
"+ex.Message+"\n");
return-1;
}
returnport;
}
///
///获取本机局域网IP地址
///
///
privatestringreturnIpAddress()
{
IPAddress[]AddressList=Dns.GetHostByName(Dns.GetHostName()).AddressList;
if(AddressList.Length<1)
{
return"";
}
returnAddressList[0].ToString();
}
///
///获得拨号动态分配IP地址
///
///
privatestaticstringgetDynamicIPAddress()
{
IPAddress[]AddressList=Dns.GetHostByName(Dns.GetHostName()).AddressList;
if(AddressList.Length<2)
{
return"";
}
returnAddressList[1].ToString();
}
///
///更新显示信息
///
///
publicvoidUpdateMsg(stringmsg)
{
Invoke(newAppendMsgEventHandler(AppendMsgEvent),rbChatContent,msg+"\n");
}
///
///添加用户更新界面
///
///
publicvoidAddUser(stringname)
{
stringstr="【"+name+"】"+"已经加入聊天!
\n";
Invoke(newAppendMsgEventHandler(AppendMsgEvent),rbChatContent,str);//AppendMsgEvent(rbChatContent,"【"+name+"】"+"已经加入聊天!
\n");
//将刚加入的用户添加进用户列表
Invoke(newAppendUserEventHandler(AppendUserEvent),lbOnlineUser,name);
this.tslOnlineUserNum.Text=Convert.ToString(clients.Count);
}
publicvoidAppendMsgEvent(RichTextBoxrb,stringmsg)
{
rb.AppendText(msg);
}
publicvoidAppendUserEvent(ListBoxlb,stringusername)
{
lb.Items.Add(username);
}
///
///获取用户列表
///
///
publicstringGetUserList()
{
stringuserList="";
for(inti=0;i { userList=userList+lbOnlineUser.Items[i].ToString()+"|"; } returnuserList; } /// ///移出用户 /// /// publicvoidRemoveUser(stringname) { this.rbChatContent.AppendText(name+"已经离开聊天室\n"); //将刚连接的用户名加入到当前在线用户列表中 this.lbOnlineUser.Items.Remove(name); this.tslOnlineUserNum.Text=System.Convert.ToString(clients.Count); } //停止服务器 privatevoidbtStopServer_Click(objectsender,EventArgse) { frmServerMain.ServerFlag=false; btStartServer.Enabled=true; btStopServer.Enabled=false; UpdateMsg("服务器已经停止监听.\n"); } //关闭窗体 privatevoidfrmServerMain_FormClosing(objectsender,FormClosingEventArgse) { frmServerMain.ServerFlag=false; } privatevoidtbServerPort_TextChanged(objectsender,EventArgse) { this.btStartServer.Enabled=(this.tbServerPort.Text! =""); } privatevoidfrmServerMain_Load(objectsender,EventArgse) { } } publicclassChatClient { privatestringname; privateSocketcurrentSocket=null; privatestringipAddress; privatefrmServerMainserver; //保留当前连接的状态 //CLOSED-->CONNECTED-->CLOSED stringconnState="closed"; publicChatClient(frmServerMainserver,SocketcurrentSocket) { this.server=server; this.currentSocket=currentSocket; } publicstringName { get{returnname;} set{name=value;} } publicSocketCurrentSocket { get{returncurrentSocket;} set{currentSocket=value;} } publicstringIpAddress { get{returnipAddress;} } //获取远程IP地址 privatestringgetRemoteIp() { return((IPEndPoint)currentSocket.RemoteEndPoint).Address.ToString(); } //和客户端进行数据通信,包括接收客户端的请求 //根据不同的请求命令,执行相应的操作,并将操作结果返回给客户端 publicvoidClientService() { string[]acceptStr=null;//保存消息字符 byte[]buff=newbyte[1024];//缓冲区 boolkeepConnected=true; //用循环不断地与客户端进行交互,直到其发出EXIT或者QUIT命令 //将keepConnected设置为false,退出循环,关闭当前连接,中止当前线程 while(keepConnected&&frmServerMain.ServerFlag) { acceptStr=null; try { if(currentSocket==null||currentSocket.Available<1) { Thread.Sleep(300); continue; } //接收信息存入buff数组中 intlength=currentSocket.Receive(buff); //将字符数组转换为字符串 stringCommand=Encoding.Default.GetString(buff,0,length); //对字符串按分隔符拆分 acceptStr=Command.Split(newchar[]{'|'}); if(acceptStr==null) { Thread.Sleep(200); continue; } } catch(Exceptionex) { server.UpdateMsg("程序发生异常,异常信息: "+ex.Message); } if(acceptStr[0]=="CONNECT") { //如果为CONECT,则它的命令格式为“CONNECT|发送者的用户名: 附件信息” //则acceptStr[1]保存的就是用户名 this.name=acceptStr[1]; if(frmServerMain.clients.Contains(this.name)) { SendToClient(this,"ERORR|User"+this.name+"已经存在! "); } else { HashtablesynClients=Hashtable.Synchronized(frmServerMain.clients); synClients.Add(this.name,this); //更新界面 server.AddUser(this.name); //对每一个在线用户发送JOIN和LIST消息命令更新用户列表 IEnumeratormyIEnumerator=frmServerMain.clients.Values.GetEnumerator(); while(myIEnumerator.MoveNext()) { ChatClientcClient=(ChatClient)myIEnumerator.Current; SendToClient(cClient,"JOIN|"+this.name+"|"); Thread.Sleep(100); } //更新连接状态 connState="connected"; SendToClient(this,"OK"); //向客户端发送LIST命令更新用户列表 stringmsgUsers="LIST|"+server.GetUserList(); SendToClient(this,msgUsers); } } elseif(acceptStr[0]=="LIST") { if(connState=="CONNECTED") { //向客户端发送LIST命令,以此更新客户端的当前在线用户列表 stringmsgUsers="LIST|"+server.GetUserList(); SendToClient(this,msgUsers); } else { SendToClient(this,"ERROR|服务器未连接,请重新登录"); } } elseif(acceptStr[0]=="CHAT") { if(connState=="connected") { //此时接收到的命令的格式为: //命令标志符(CHAT)|发送者的用户名: 发送内容| //向所有当前在线的用户转发此信息 IEnumeratormyEnumerator=frmServerMain.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 聊天软件 聊天 软件