




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第C#基于WebSocket實現(xiàn)聊天室功能本文實例為大家分享了C#基于WebSocket實現(xiàn)聊天室功能的具體代碼,供大家參考,具體內(nèi)容如下
前面兩篇溫習了,C#Socket內(nèi)容
本章根據(jù)Socket異步聊天室修改成WebSocket聊天室
WebSocket特別的地方是握手和消息內(nèi)容的編碼、解碼(添加了ServerHelper協(xié)助處理)
ServerHelper:
usingSystem;
usingSystem.Collections;
usingSystem.Text;
usingSystem.Security.Cryptography;
namespaceSocketDemo
//Server助手負責:1握手2請求轉(zhuǎn)換3響應轉(zhuǎn)換
classServerHelper
{
///summary
///輸出連接頭信息
////summary
publicstaticstringResponseHeader(stringrequestHeader)
{
Hashtabletable=newHashtable();
//拆分成鍵值對,保存到哈希表
string[]rows=requestHeader.Split(newstring[]{"\r\n"},StringSplitOptions.RemoveEmptyEntries);
foreach(stringrowinrows)
{
intsplitIndex=row.IndexOf(':');
if(splitIndex0)
{
table.Add(row.Substring(0,splitIndex).Trim(),row.Substring(splitIndex+1).Trim());
}
}
StringBuilderheader=newStringBuilder();
header.Append("HTTP/1.1101WebSocketProtocolHandshake\r\n");
header.AppendFormat("Upgrade:{0}\r\n",table.ContainsKey("Upgrade")table["Upgrade"].ToString():string.Empty);
header.AppendFormat("Connection:{0}\r\n",table.ContainsKey("Connection")table["Connection"].ToString():string.Empty);
header.AppendFormat("WebSocket-Origin:{0}\r\n",table.ContainsKey("Sec-WebSocket-Origin")table["Sec-WebSocket-Origin"].ToString():string.Empty);
header.AppendFormat("WebSocket-Location:{0}\r\n",table.ContainsKey("Host")table["Host"].ToString():string.Empty);
stringkey=table.ContainsKey("Sec-WebSocket-Key")table["Sec-WebSocket-Key"].ToString():string.Empty;
stringmagic="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
header.AppendFormat("Sec-WebSocket-Accept:{0}\r\n",Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key+magic))));
header.Append("\r\n");
returnheader.ToString();
}
///summary
///解碼請求內(nèi)容
////summary
publicstaticstringDecodeMsg(Byte[]buffer,intlen)
{
if(buffer[0]!=0x81
||(buffer[0]0x80)!=0x80
||(buffer[1]0x80)!=0x80)
{
returnnull;
}
Byte[]mask=newByte[4];
intbeginIndex=0;
intpayload_len=buffer[1]0x7F;
if(payload_len==0x7E)
{
Array.Copy(buffer,4,mask,0,4);
payload_len=payload_len0x00000000;
payload_len=payload_len|buffer[2];
payload_len=(payload_len8)|buffer[3];
beginIndex=8;
}
elseif(payload_len!=0x7F)
{
Array.Copy(buffer,2,mask,0,4);
beginIndex=6;
}
for(inti=0;ipayload_len;i++)
{
buffer[i+beginIndex]=(byte)(buffer[i+beginIndex]^mask[i%4]);
}
returnEncoding.UTF8.GetString(buffer,beginIndex,payload_len);
}
///summary
///編碼響應內(nèi)容
////summary
publicstaticbyte[]EncodeMsg(stringcontent)
{
byte[]bts=null;
byte[]temp=Encoding.UTF8.GetBytes(content);
if(temp.Length126)
{
bts=newbyte[temp.Length+2];
bts[0]=0x81;
bts[1]=(byte)temp.Length;
Array.Copy(temp,0,bts,2,temp.Length);
}
elseif(temp.Length0xFFFF)
{
bts=newbyte[temp.Length+4];
bts[0]=0x81;
bts[1]=126;
bts[2]=(byte)(temp.Length0xFF);
bts[3]=(byte)(temp.Length80xFF);
Array.Copy(temp,0,bts,4,temp.Length);
}
else
{
byte[]st=System.Text.Encoding.UTF8.GetBytes(string.Format("暫不處理超長內(nèi)容").ToCharArray());
}
returnbts;
}
}
}
Server:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Net;
usingSystem.Net.Sockets;
namespaceSocketDemo
classClientInfo
{
publicSocketSocket{get;set;}
publicboolIsOpen{get;set;}
publicstringAddress{get;set;}
}
//管理Client
classClientManager
{
staticListClientInfoclientList=newListClientInfo
publicstaticvoidAdd(ClientInfoinfo)
{
if(!IsExist(info.Address))
{
clientList.Add(info);
}
}
publicstaticboolIsExist(stringaddress)
{
returnclientList.Exists(item=string.Compare(address,item.Address,true)==0);
}
publicstaticboolIsExist(stringaddress,boolisOpen)
{
returnclientList.Exists(item=string.Compare(address,item.Address,true)==0item.IsOpen==isOpen);
}
publicstaticvoidOpen(stringaddress)
{
clientList.ForEach(item=
{
if(string.Compare(address,item.Address,true)==0)
{
item.IsOpen=true;
}
});
}
publicstaticvoidClose(stringaddress=null)
{
clientList.ForEach(item=
{
if(address==null||string.Compare(address,item.Address,true)==0)
{
item.IsOpen=false;
item.Socket.Shutdown(SocketShutdown.Both);
}
});
}
//發(fā)送消息到ClientList
publicstaticvoidSendMsgToClientList(stringmsg,stringaddress=null)
{
clientList.ForEach(item=
{
if(item.IsOpen(address==null||item.Address!=address))
{
SendMsgToClient(item.Socket,msg);
}
});
}
publicstaticvoidSendMsgToClient(Socketclient,stringmsg)
{
byte[]bt=ServerHelper.EncodeMsg(msg);
client.BeginSend(bt,0,bt.Length,SocketFlags.None,newAsyncCallback(SendTarget),client);
}
privatestaticvoidSendTarget(IAsyncResultres)
{
//Socketclient=(Socket)res.AsyncState;
//intsize=client.EndSend(res);
}
}
//接收消息
classReceiveHelper
{
publicbyte[]Bytes{get;set;}
publicvoidReceiveTarget(IAsyncResultres)
{
Socketclient=(Socket)res.AsyncState;
intsize=client.EndReceive(res);
if(size0)
{
stringaddress=client.RemoteEndPoint.ToString();//獲取Client的IP和端口
stringstringdata=null;
if(ClientManager.IsExist(address,false))//握手
{
stringdata=Encoding.UTF8.GetString(Bytes,0,size);
ClientManager.SendMsgToClient(client,ServerHelper.ResponseHeader(stringdata));
ClientManager.Open(address);
}
else
{
stringdata=ServerHelper.DecodeMsg(Bytes,size);
}
if(stringdata.IndexOf("exit")-1)
{
ClientManager.SendMsgToClientList(address+"已從服務器斷開",address);
ClientManager.Close(address);
Console.WriteLine(address+"已從服務器斷開");
Console.WriteLine(address+""+DateTimeOffset.Now.ToString("G"));
return;
}
else
{
Console.WriteLine(stringdata);
Console.WriteLine(address+""+DateTimeOffset.Now.ToString("G"));
ClientManager.SendMsgToClientList(stringdata,address);
}
}
//繼續(xù)等待
client.BeginReceive(Bytes,0,Bytes.Length,SocketFlags.None,newAsyncCallback(ReceiveTarget),client);
}
}
//監(jiān)聽請求
classAcceptHelper
{
publicbyte[]Bytes{get;set;}
publicvoidAcceptTarget(IAsyncResultres)
{
Socketserver=(Socket)res.AsyncState;
Socketclient=server.EndAccept(res);
stringaddress=client.RemoteEndPoint.ToString();
ClientManager.Add(newClientInfo(){Socket=client,Address=address,IsOpen=false});
ReceiveHelperrs=newReceiveHelper(){Bytes=this.Bytes};
IAsyncResultrecres=client.BeginReceive(rs.Bytes,0,rs.Bytes.Length,SocketFlags.None,newAsyncCallback(rs.ReceiveTarget),client);
//繼續(xù)監(jiān)聽
server.BeginAccept(newAsyncCallback(AcceptTarget),server);
}
}
classProgram
{
staticvoidMain(string[]args)
{
Socketserver=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
server.Bind(newIPEndPoint(IPAddress.Parse(""),200));//綁定IP+端口
server.Listen(10);//開始監(jiān)聽
Console.WriteLine("等待連接...");
AcceptHelperca=newAcceptHelper(){Bytes=newbyte[2048]};
IAsyncResultres=server.BeginAccept(newAsyncCallback(ca.AcceptTarget),server);
stringstr=string.Empty;
while(str!="exit")
{
str=Console.ReadLine();
Console.WriteLine("ME:"+DateTimeOffset.Now.ToString("G"));
ClientManager.SendMsgToClientList(str);
}
ClientManager.Close();
server.Close();
}
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025至2030中國白銀行業(yè)市場發(fā)展分析及發(fā)展趨勢與投資前景報告
- 2025至2030中國男式化妝品行業(yè)市場發(fā)展現(xiàn)狀及發(fā)展前景與投資風險報告
- 2025至2030中國甘蔗榨汁機械行業(yè)深度研究及發(fā)展前景投資評估分析
- 招聘培訓課件素材
- 教育心理學在家庭環(huán)境中的實踐-以培養(yǎng)孩子同理心為例的探索研究
- 教育科技倫理視角下的創(chuàng)新與責任
- 企業(yè)教育培訓的科技倫理要求及實現(xiàn)途徑
- 教育設施與節(jié)能環(huán)保的完美結(jié)合
- 智慧教室中的情緒識別與干預策略研究
- 抖音商戶運營經(jīng)理直播后復盤會議制度
- 21ZJ111 變形縫建筑構(gòu)造
- 暨南大學視聽說聽力材料part 2 A文章
- GB/T 42567.1-2023工業(yè)過程測量變送器試驗的參比條件和程序第1部分:所有類型變送器的通用程序
- 2023年成都市成華區(qū)數(shù)學六年級第二學期期末教學質(zhì)量檢測模擬試題含解析
- QC提高土工格柵加筋擋土墻施工質(zhì)量中鐵
- 現(xiàn)代大學英語-第三版-精讀3-教師教案
- 專升本《城市管理學》-試卷-答案
- 說儒(上、下)-胡適文檔全文預覽
- 《協(xié)和醫(yī)院護理專家 月嫂培訓手冊》讀書筆記思維導圖PPT模板下載
- 小學六年級數(shù)學計算題100道(含答案)
- 2023年《中藥學綜合知識與技能》高分通關(guān)題庫600題(附答案)
評論
0/150
提交評論