C#WebSocket 채팅방
이 장은 Socket 비동기 채팅방에 따라 WebSocket 채팅방으로 수정한다
웹소켓의 특별한 점은 악수와 메시지 내용의 인코딩, 디코딩(ServerHelper 협조 처리 추가)이다.
ServerHelper:
using System;
using System.Collections;
using System.Text;
using System.Security.Cryptography;
namespace SocketDemo
{
// Server :1 2 3
class ServerHelper
{
///
///
///
public static string ResponseHeader(string requestHeader)
{
Hashtable table = new Hashtable();
// ,
string[] rows = requestHeader.Split(new string[] { "\r
" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string row in rows)
{
int splitIndex = row.IndexOf(':');
if (splitIndex > 0)
{
table.Add(row.Substring(0, splitIndex).Trim(), row.Substring(splitIndex + 1).Trim());
}
}
StringBuilder header = new StringBuilder();
header.Append("HTTP/1.1 101 Web Socket Protocol Handshake\r
");
header.AppendFormat("Upgrade: {0}\r
", table.ContainsKey("Upgrade") ? table["Upgrade"].ToString() : string.Empty);
header.AppendFormat("Connection: {0}\r
", table.ContainsKey("Connection") ? table["Connection"].ToString() : string.Empty);
header.AppendFormat("WebSocket-Origin: {0}\r
", table.ContainsKey("Sec-WebSocket-Origin") ? table["Sec-WebSocket-Origin"].ToString() : string.Empty);
header.AppendFormat("WebSocket-Location: {0}\r
", table.ContainsKey("Host") ? table["Host"].ToString() : string.Empty);
string key = table.ContainsKey("Sec-WebSocket-Key") ? table["Sec-WebSocket-Key"].ToString() : string.Empty;
string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
header.AppendFormat("Sec-WebSocket-Accept: {0}\r
", Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + magic))));
header.Append("\r
");
return header.ToString();
}
///
///
///
public static string DecodeMsg(Byte[] buffer, int len)
{
if (buffer[0] != 0x81
|| (buffer[0] & 0x80) != 0x80
|| (buffer[1] & 0x80) != 0x80)
{
return null;
}
Byte[] mask = new Byte[4];
int beginIndex = 0;
int payload_len = buffer[1] & 0x7F;
if (payload_len == 0x7E)
{
Array.Copy(buffer, 4, mask, 0, 4);
payload_len = payload_len & 0x00000000;
payload_len = payload_len | buffer[2];
payload_len = (payload_len << 8) | buffer[3];
beginIndex = 8;
}
else if (payload_len != 0x7F)
{
Array.Copy(buffer, 2, mask, 0, 4);
beginIndex = 6;
}
for (int i = 0; i < payload_len; i++)
{
buffer[i + beginIndex] = (byte)(buffer[i + beginIndex] ^ mask[i % 4]);
}
return Encoding.UTF8.GetString(buffer, beginIndex, payload_len);
}
///
///
///
public static byte[] EncodeMsg(string content)
{
byte[] bts = null;
byte[] temp = Encoding.UTF8.GetBytes(content);
if (temp.Length < 126)
{
bts = new byte[temp.Length + 2];
bts[0] = 0x81;
bts[1] = (byte)temp.Length;
Array.Copy(temp, 0, bts, 2, temp.Length);
}
else if (temp.Length < 0xFFFF)
{
bts = new byte[temp.Length + 4];
bts[0] = 0x81;
bts[1] = 126;
bts[2] = (byte)(temp.Length & 0xFF);
bts[3] = (byte)(temp.Length >> 8 & 0xFF);
Array.Copy(temp, 0, bts, 4, temp.Length);
}
else
{
byte[] st = System.Text.Encoding.UTF8.GetBytes(string.Format(" ").ToCharArray());
}
return bts;
}
}
}
Server: using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SocketDemo
{
class ClientInfo
{
public Socket Socket { get; set; }
public bool IsOpen { get; set; }
public string Address { get; set; }
}
// Client
class ClientManager
{
static List clientList = new List();
public static void Add(ClientInfo info)
{
if (!IsExist(info.Address))
{
clientList.Add(info);
}
}
public static bool IsExist(string address)
{
return clientList.Exists(item => string.Compare(address, item.Address, true) == 0);
}
public static bool IsExist(string address, bool isOpen)
{
return clientList.Exists(item => string.Compare(address, item.Address, true) == 0 && item.IsOpen == isOpen);
}
public static void Open(string address)
{
clientList.ForEach(item =>
{
if (string.Compare(address, item.Address, true) == 0)
{
item.IsOpen = true;
}
});
}
public static void Close(string address = null)
{
clientList.ForEach(item =>
{
if (address == null || string.Compare(address, item.Address, true) == 0)
{
item.IsOpen = false;
item.Socket.Shutdown(SocketShutdown.Both);
}
});
}
// ClientList
public static void SendMsgToClientList(string msg, string address = null)
{
clientList.ForEach(item =>
{
if (item.IsOpen && (address == null || item.Address != address))
{
SendMsgToClient(item.Socket, msg);
}
});
}
public static void SendMsgToClient(Socket client, string msg)
{
byte[] bt = ServerHelper.EncodeMsg(msg);
client.BeginSend(bt, 0, bt.Length, SocketFlags.None, new AsyncCallback(SendTarget), client);
}
private static void SendTarget(IAsyncResult res)
{
//Socket client = (Socket)res.AsyncState;
//int size = client.EndSend(res);
}
}
//
class ReceiveHelper
{
public byte[] Bytes { get; set; }
public void ReceiveTarget(IAsyncResult res)
{
Socket client = (Socket)res.AsyncState;
int size = client.EndReceive(res);
if (size > 0)
{
string address = client.RemoteEndPoint.ToString(); // Client IP
string stringdata = 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);
}
}
//
client.BeginReceive(Bytes, 0, Bytes.Length, SocketFlags.None, new AsyncCallback(ReceiveTarget), client);
}
}
//
class AcceptHelper
{
public byte[] Bytes { get; set; }
public void AcceptTarget(IAsyncResult res)
{
Socket server = (Socket)res.AsyncState;
Socket client = server.EndAccept(res);
string address = client.RemoteEndPoint.ToString();
ClientManager.Add(new ClientInfo() { Socket = client, Address = address, IsOpen = false });
ReceiveHelper rs = new ReceiveHelper() { Bytes = this.Bytes };
IAsyncResult recres = client.BeginReceive(rs.Bytes, 0, rs.Bytes.Length, SocketFlags.None, new AsyncCallback(rs.ReceiveTarget), client);
//
server.BeginAccept(new AsyncCallback(AcceptTarget), server);
}
}
class Program
{
static void Main(string[] args)
{
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 200)); // IP+
server.Listen(10); //
Console.WriteLine(" ...");
AcceptHelper ca = new AcceptHelper() { Bytes = new byte[2048] };
IAsyncResult res = server.BeginAccept(new AsyncCallback(ca.AcceptTarget), server);
string str = string.Empty;
while (str != "exit")
{
str = Console.ReadLine();
Console.WriteLine("ME: " + DateTimeOffset.Now.ToString("G"));
ClientManager.SendMsgToClientList(str);
}
ClientManager.Close();
server.Close();
}
}
}
Client:
var mySocket;
function Star() {
mySocket = new WebSocket("ws://127.0.0.1:200", "my-custom-protocol");
mySocket.onopen = function Open() {
Show(" ");
};
mySocket.onmessage = function (evt) {
Show(evt.data);
};
mySocket.onclose = function Close() {
Show(" ");
mySocket.close();
};
}
function Send() {
var content = document.getElementById("content").value;
Show(content);
mySocket.send(content);
}
function Show(msg) {
var roomContent = document.getElementById("roomContent");
roomContent.innerHTML = msg + "<br/>" + roomContent.innerHTML;
}
<div id="roomContent" style="width: 500px; height: 200px; overflow: hidden; border: 2px solid #686868;
margin-bottom: 10px; padding: 10px 0px 0px 10px;">
</div>
<div>
<textarea id="content" cols="50" rows="3" style="padding: 10px 0px 0px 10px;"/>
</div>
<input type="button" value="Connection"/>
<input type="button" value="Send"/>
</code></pre>
<br/>
<p><br/></p>
</div>
</div>
</div>
</div>
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Java는 Socket 종료 스레드를 닫습니다.본고의 실례는 여러분에게 자바 닫기 소켓의 종료 라인을 실현하는 구체적인 코드를 공유하여 참고하도록 하였으며, 구체적인 내용은 다음과 같다. 이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.