基于Socket的聊天室C#版.docx
《基于Socket的聊天室C#版.docx》由会员分享,可在线阅读,更多相关《基于Socket的聊天室C#版.docx(32页珍藏版)》请在冰豆网上搜索。
基于Socket的聊天室C#版
基于Socket的聊天室(C#版)
一、服务器/客户端聊天室模型
1.首先启动聊天室服务器,使得TcpListener开始监听端口,此时TcpListener会进入Pending状态,等待客户端连接;
2.其次,当有客户端连接后,通过AccepSocket返回与客户端连接的Socket对象,然后通过读写Socket对象完成与聊天室客户端的数据传输。
聊天室客户端成功启动后,首先创建一个Socket对象,然后通过这个Socket对象连接聊天室服务器,连接成功后开通Socket完成数据的接收和发送处理。
二、系统功能设计
本设计为一个简单的聊天室工具,设计基本的聊天功能,如聊天、列表维护等。
系统主要为两大块:
聊天室服务器及聊天室客户端。
服务器界面设计如下:
客户端界面设计如下:
三、聊天协议的应答
A—网络—B
主机与主机通信主要识别身份(标识设备用IP)及通信协议
网络应用程序——端口号——接收数据
注:
1.IP地址是总机,端口号是分机(传输层)
2.端口号为16位二进制数,范围0到65535,但实际编程只能用1024以上端口号
Socket编程
首先,我们了解常用网络编程协议。
我们用得最多的协议是UDP和TCP,UDP是不可靠传输服务,TCP是可靠传输服务。
UDP就像点对点的数据传输一样,发送者把数据打包,包上有收信者的地址和其他必要信息,至于收信者能不能收到,UDP协议并不保证。
而TCP协议就像(实际他们是一个层次的网络协议)是建立在UDP的基础上,加入了校验和重传等复杂的机制来保证数据可靠的传达到收信者。
一个是面向连接一个无连接,各有用处,在一些数据传输率高的场合如视频会议倾向于UDP,而对一些数据安全要求高的地方如下载文件就倾向于TCP。
Socket————网络应用程序
电话机————访问通信协议
聊天协议的应答:
聊天状态:
CLOSED和CONNECTED状态
执行CONN命令后进入CONNECTED状态,执行下列命令:
CONN:
连接聊天室服务器
JOIN:
加入聊天(通知其他用户本人已经加入聊天室服务器)
LIST:
列出所有的用户(向客户端发送全部的登录用户名字)
CHAT:
发送聊天信息(公开的聊天信息)
PRIV:
进行私聊(三个参数:
私聊信息用户;接收私聊信息用户;发送信息)
EXIT:
客户端向服务器发送离开请求;
QUIT:
退出聊天,服务器向客户端发送退出命令(执行QUIT命令聊天状态变为CLOSED)
四、系统实现
服务器协议解析:
当有客户端连接聊天室服务器后,服务器立刻为这个客户建立一个数据接收的线程(多用户程序必备)。
在接收线程中,如果收到聊天命令,就对其进行解析处理,服务器可以处理五种命令:
CONN\LIST\CHAT\PRIV\EXIT。
服务器接收到CONN命令,就向其他用户发送JOIN命令告诉有用户加入,然后把当前的全部用户信息返回给刚刚加入的用户,以便在界面上显示用户列表。
当接收到EXIT命令后,就清除当前用户的信息,然后向其他用户发送QUIT命令,告诉其他用户退出了,这些用户的客户端把离开的用户从用户列表中删除。
internalstaticHashtableclients=newHashtable();//clients数组保存当前在线用户的client对象
privateTcpListenerlistener;//该服务器默认的监听端口号
staticintMAX_NUM=100;//服务器可以支持的客户端的最大连接数
internalstaticboolSocketServiceFlag=false;//开始服务的标志
//获得本地局域网或者拨号动态分配的IP地址,在启动服务器时会用到IP地址
privatestringgetIPAddress()
{
//获得本机局域网IP地址
IPAddress[]Addresslist=Dns.GetHostEntry(Dns.GetHostName()).AddressList;
if(Addresslist.Length<1)
{
return"";
}
returnAddresslist[0].ToString();
}
//获得动态的IP地址
privatestaticstringgetDynamicIPAddress()
{
IPAddress[]Addresslist=Dns.GetHostEntry(Dns.GetHostName()).AddressList;
if(Addresslist.Length<2)
{
return"";
}
returnAddresslist[1].ToString();
}
//服务器监听的端口号通过getValidPort()函数获得
privateintgetValidPort(stringport)
{
intlport;
//测试端口号是否有效
try
{
//是否为空
if(port=="")
{
thrownewArgumentException("端口号为空,不能启动服务器");
}
lport=System.Convert.ToInt32(port);
}
catch(Exceptione)
{
Console.WriteLine("无效的端口号:
"+e.ToString());
this.rtbSocketMsg.AppendText("无效的端口号:
"+e.ToString()+"\n");
return-1;
}
returnlport;
}
privatevoidbtnSocketStart_Click(objectsender,EventArgse)
{
intport=getValidPort(tbSocketPort.Text);
if(port<0)
{
return;
}
stringip=this.getIPAddress();
try
{
IPAddressipAdd=IPAddress.Parse(ip);
listener=newTcpListener(ipAdd,port);//创建服务器套接字
listener.Start();//开始监听服务器端口
this.rtbSocketMsg.AppendText("Socket服务器已经启动,正在监听"
+ip+"端口号:
"+this.tbSocketPort.Text+"\n");
//启动一个新的线程,执行方法this.StartSocketListen,
//以便在一个独立的进程中执行确认与客户端Socket连接的操作
Form1.SocketServiceFlag=true;
Threadthread=newThread(newThreadStart(this.StartSocketListen));
thread.Start();
this.btnSocketStart.Enabled=false;
this.btnSocketStop.Enabled=true;
}
catch(Exceptionex)
{
this.rtbSocketMsg.AppendText(ex.Message.ToString()+"\n");
}
}
//在新的线程中的操作,它主要用于当接收到一个客户端请求时,确认与客户端的链接
//并且立刻启动一个新的线程来处理和该客户端的信息交互
privatevoidStartSocketListen()
{
while(Form1.SocketServiceFlag)
{
try
{
//当接收到一个客户端请求时,确认与客户端的链接
if(listener.Pending())//确认是否有挂起的连接请求
{
Socketsocket=listener.AcceptSocket();//接收挂起的连接请求
if(clients.Count>=MAX_NUM)
{
this.rtbSocketMsg.AppendText("已经达到了最大连接数:
"+MAX_NUM+",拒绝新的链接\n");
socket.Close();
}
else
{
//启动一个新的线程
//执行方法this.ServiceClient,处理用户相应的请求
ChatSever.Client.Clientclient=newChatSever.Client.Client(this,socket);
ThreadclientService=newThread(newThreadStart(client.ServiceClient));
clientService.Start();
}
}
Thread.Sleep(200);//提高性能整体速度,原因不详
}
catch(Exceptionex)
{
this.rtbSocketMsg.AppendText(ex.Message.ToString()+"\n");
}
}
}
privatevoidtbSocketPort_TextChanged(objectsender,EventArgse)
{
if(this.tbSocketPort.Text!
="")
{
this.btnSocketStart.Enabled=true;
}
}
//下面为一些界面处理函数
privatevoidbtnSocketStop_Click(objectsender,EventArgse)
{
Form1.SocketServiceFlag=false;
this.btnSocketStart.Enabled=true;
this.btnSocketStop.Enabled=false;
}
publicvoidaddUser(stringusername)
{
this.rtbSocketMsg.AppendText(username+"已经加入\n");//将刚连接的用户名加入到当前在线用户列表中
this.lbSocketClients.Items.Add(username);
this.tbSocketClientsNum.Text=System.Convert.ToString(clients.Count);
}
publicvoidremoveUser(stringusername)
{
this.rtbSocketMsg.AppendText(username+"已经离开\n");//将刚连接的用户名加入到当前在线用户列表中
this.lbSocketClients.Items.Remove(username);
this.tbSocketClientsNum.Text=System.Convert.ToString(clients.Count);
}
publicstringGetUserList()
{
string