根据Socket的聊天室C版Word文档下载推荐.docx
- 文档编号:8350732
- 上传时间:2023-05-11
- 格式:DOCX
- 页数:32
- 大小:280.69KB
根据Socket的聊天室C版Word文档下载推荐.docx
《根据Socket的聊天室C版Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《根据Socket的聊天室C版Word文档下载推荐.docx(32页珍藏版)》请在冰点文库上搜索。
连接聊天室服务器
JOIN:
加入聊天(通知其他用户本人已经加入聊天室服务器)
LIST:
列出所有的用户(向客户端发送全部的登录用户名字)
CHAT:
发送聊天信息(公开的聊天信息)
PRIV:
进行私聊(三个参数:
私聊信息用户;
接收私聊信息用户;
发送信息)
EXIT:
客户端向服务器发送离开请求;
QUIT:
退出聊天,服务器向客户端发送退出命令(执行QUIT命令聊天状态变为CLOSED)
四、系统实现
服务器协议解析:
当有客户端连接聊天室服务器后,服务器立刻为这个客户建立一个数据接收的线程(多用户程序必备)。
在接收线程中,如果收到聊天命令,就对其进行解析处理,服务器可以处理五种命令:
CONN\LIST\CHAT\PRIV\EXIT。
服务器接收到CONN命令,就向其他用户发送JOIN命令告诉有用户加入,然后把当前的全部用户信息返回给刚刚加入的用户,以便在界面上显示用户列表。
当接收到EXIT命令后,就清除当前用户的信息,然后向其他用户发送QUIT命令,告诉其他用户退出了,这些用户的客户端把离开的用户从用户列表中删除。
聊天室客户端的协议解析:
当客户端连接到服务器后,服务器立刻建立一个数据接收的独立线程。
在接收线程中,如果收到了聊天命令,就对其进行解析处理。
聊天室客户端一共处理的命令有五种:
OK\ERR\LIST\JOIN\QUIT命令。
五、程序设计(代码)
服务器端设计:
引入网络操作命名空间System.Net、System.Net.Sockets;
线程处理命名空间System.Threading
第一步:
界面设计及类与相关成员的定义
对界面进行设计(简单)
对内部函数进行设计(要编写一个独立的类即Client类,封装了客户端的信息与连接,每一个客户进入聊天室,就创建一个Client对象,用于保存该用户的信息并接收用户数据和发送信息到客户端)
几个重要的类:
TcpListener类(服务器套接字创建)、Socket类
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)
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();
IPAddressipAdd=IPAddress.Parse(ip);
listener=newTcpListener(ipAdd,port);
//创建服务器套接字
listener.Start();
//开始监听服务器端口
Socket服务器已经启动,正在监听"
+ip+"
端口号:
+this.tbSocketPort.Text+"
//启动一个新的线程,执行方法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()+"
//在新的线程中的操作,它主要用于当接收到一个客户端请求时,确认与客户端的链接
//并且立刻启动一个新的线程来处理和该客户端的信息交互
privatevoidStartSocketListen()
while(Form1.SocketServiceFlag)
//当接收到一个客户端请求时,确认与客户端的链接
if(listener.Pending())//确认是否有挂起的连接请求
Socketsocket=listener.AcceptSocket();
//接收挂起的连接请求
if(clients.Count>
=MAX_NUM)
已经达到了最大连接数:
+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);
//提高性能整体速度,原因不详
privatevoidtbSocketPort_TextChanged(objectsender,EventArgse)
if(this.tbSocketPort.Text!
="
this.btnSocketStart.Enabled=true;
//下面为一些界面处理函数
privatevoidbtnSocketStop_Click(objectsender,EventArgse)
Form1.SocketServiceFlag=false;
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)
已经离开\n"
//将刚连接的用户名加入到当前在线用户列表中
this.lbSocketClients.Items.Remove(username);
publicstringGetUserList()
stringRtn="
for(inti=0;
i<
lbSocketClients.Items.Count;
i++)
Rtn+=lbSocketClients.Items[i].ToString()+"
|"
returnRtn;
publicvoidupdateUI(stringmsg)
this.rtbSocketMsg.AppendText(msg+"
privatevoidForm1_FormClosing(objectsender,FormClosingEventArgse)
//下面为Client类定义
publicclassClient
privatestringname;
//保存用户名
privateSocketcurrentSocket=null;
//保存与当前用户连接的Socket对象
privatestringipAddress;
//保存用户的IP地址
privateForm1server;
//保存当前连接状态
//Closed--connected--closed
privatestringstate="
closed"
publicClient(Form1server,SocketclientSocket)
this.server=server;
this.currentSocket=clientSocket;
ipAddress=getRemoteIPAddress();
publicstringName
get
returnname;
set
name=value;
publicSocketCurrentSocket
returncurrentSocket;
//ipAddress
privatestringgetRemoteIPAddress()
return((IPEndPoint)currentSocket.RemoteEndPoint).Address.ToString();
//SendToClient()方法实现了向客户端发送命令请求的功能
privatevoidSendToClient(Clientclient,stringmsg)
System.Byte[]message=System.Text.Encoding.Default.GetBytes(msg.ToCharArray());
client.currentSocket.Send(message,message.Length,0);
//ServiceClient方法用于和客户端进行数据通信,包括接收客户端的请求
//它根据不同的请求命令执行相应的操作,并将处理结果返回到客户端
//ServiceClient()函数为服务器接收客户数据的线程主体,主要用来接收用户发送来的数据,并处理聊天命令
publicvoidServiceClient()
string[]tokens=null;
byte[]buff=newbyte[1024];
boolkeepConnect=true;
//用循环来不断地与客户端进行交互,直到客户端发出“EXIT”命令
//将keepConnect职为false,退出循环,关闭连接,并中止当前线程
while(keepConnect&
&
Form1.SocketServiceFlag)
//tokens=null;
if(currentSocket==null||currentSocket.Available<
Thread.Sleep(300);
continue;
//接收数据并存入BUFF数组中
intlen=currentSocket.Receive(buff);
//将字符数组转化为字符串
stringclientCommand=System.Text.Encoding.Default.GetString(buff,0,len);
//tokens【0】中保存了命令标志符(CONNCHATPRIVLIST或EXIT)
tokens=clientCommand.Split(newchar[]{'
|'
});
if(tokens==null)
catch(Exceptione)
server.updateUI("
发送异常:
+e.ToString());
//以上代码主要用于服务器初始化和接收客户端发送来的数据。
它在对用户数据进行解析后,把用户命令转换为数组方式。
if(tokens[0]=="
CONN"
//此时接收到的命令格式化为命令标识符CONN|发送者的用户名|tokens[1]中保存了发送者的用户名
this.name=tokens[1];
if(Form1.clients.Contains(this.name))
SendToClient(this,"
ERR|User"
+this.name+"
已经存在"
HashtablesyncClients=Hashtable.Synchronized(Form1.clients);
syncClients.Add(this.name,this);
//更新界面
server.addUser(this.name);
//对每一个当前在线的用户发送JOIN消息命令和LIST消息命令,以此来跟新客户端的当前在线用户列表
System.Collections.IEnumeratormyEnumerator=Form1.clients.Values.GetEnumerator();
while(myEnumerator.MoveNext())
Clientclient=(Client)myEnumerator.Current;
SendToClient(client,"
JOIN|"
+tokens[1]+"
Thread.Sleep(100);
//更新状态
state="
connected"
OK"
//向客户端发送LIST命令,以此更新客户端的当前在线用户列表
stringmsgUsers="
LIST|"
+server.GetUserList();
SendToClient(this,msgUsers);
elseif(tokens[0]=="
CHAT"
if(state=="
//此时收到的命令的格式为:
命令标识符CHAT|发送者的用户名:
发送内容|向所有当前在线的用户转发此信息
//将发送者的用户名:
发送内容转发给用户
SendToClient(client,tokens[1]);
server.updateUI(tokens[1]);
//senderrtoserver
ERR|stateerror,pleaseloginfirst"
PRIV"
命令标识符PRIV|发送者的用户名:
发送内容|
//tokens[1]中保存了发生者的用户名
stringsender=tokens[1];
//tokens[2]中保存了发送者的用户名
stringreceiver=tokens[2];
//tokens[3]中保存了发送的内容
stringcontent=tokens[3];
stringmessage=sender+"
-->
+receiver+”:
”+content;
//仅将信息转发给法送者和接收者
if(Form1.clients.Contains(sender))
SendToClient((Client)Form1.clients[sender],message);
if(Form1.clients.Contains(receiver))
SendToClient((Client)Form1.clients[receiver],message);
EXIT"
{//此时收到的命令的格式为:
命令标识符EXIT|发送者的用户名:
//向所有当前在线的用户发送该用户已离开的消息
if(Form1.clients.Contains(tokens[1]))
Clientclient=(Client)Form1.clients(tokens[1]));
//将该用户对应Client对象从clients中删除
syncClients.Remove(client.name);
server.removeUser(client.name);
//向客户端发送QUIT命令
stringmessage="
QUIT|"
+tokens[1]
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 根据 Socket 聊天室