C# 聊天软件.docx

上传人:b****0 文档编号:9242618 上传时间:2023-05-17 格式:DOCX 页数:33 大小:99.65KB
下载 相关 举报
C# 聊天软件.docx_第1页
第1页 / 共33页
C# 聊天软件.docx_第2页
第2页 / 共33页
C# 聊天软件.docx_第3页
第3页 / 共33页
C# 聊天软件.docx_第4页
第4页 / 共33页
C# 聊天软件.docx_第5页
第5页 / 共33页
C# 聊天软件.docx_第6页
第6页 / 共33页
C# 聊天软件.docx_第7页
第7页 / 共33页
C# 聊天软件.docx_第8页
第8页 / 共33页
C# 聊天软件.docx_第9页
第9页 / 共33页
C# 聊天软件.docx_第10页
第10页 / 共33页
C# 聊天软件.docx_第11页
第11页 / 共33页
C# 聊天软件.docx_第12页
第12页 / 共33页
C# 聊天软件.docx_第13页
第13页 / 共33页
C# 聊天软件.docx_第14页
第14页 / 共33页
C# 聊天软件.docx_第15页
第15页 / 共33页
C# 聊天软件.docx_第16页
第16页 / 共33页
C# 聊天软件.docx_第17页
第17页 / 共33页
C# 聊天软件.docx_第18页
第18页 / 共33页
C# 聊天软件.docx_第19页
第19页 / 共33页
C# 聊天软件.docx_第20页
第20页 / 共33页
亲,该文档总共33页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

C# 聊天软件.docx

《C# 聊天软件.docx》由会员分享,可在线阅读,更多相关《C# 聊天软件.docx(33页珍藏版)》请在冰点文库上搜索。

C# 聊天软件.docx

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.

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2