C# WebSocket服务具体实现方法
HTTP 与 WebSocket之间的区别
http是单向的,只能由浏览器(客户端)发起请求,服务器(服务端)只负责接收处理信息,并返回结果,而websocket是双向的,可以由服务端发起请求到客户端,或者客户端发起请求到服务端,例如聊天室功能。
定义WebsocketConnected模型
public class WebSocketConnected
{
public IPEndPoint RemoteEndPoint {
get; set; }
public WebSocket WebSocket {
get; set; }
}
WebSocketConnected 模型结构如下:
Field | Description |
---|---|
RemoteEndPoint | 客户端地址 |
WebSocket | Web套接字 |
定义Websocket功能接口
public interface IWebSocketOperate
{
Action<WebSocketConnected, string> OnMessage {
get; set; }
Action<WebSocketConnected> OnOpen {
get; set; }
Action<WebSocketConnected> OnClose {
get; set; }
Action<WebSocketConnected, string> OnError {
get; set; }
void SendAsync(string text);
void SendAsync(string text, WebSocketConnected connected);
}
IWebSocketOperate具体功能用途如下:
Method | Description |
---|---|
OnMessage | 接收客户端消息时 |
OnOpen | 客户端连接时 |
OnClose | 客户端关闭连接时 |
OnError | 出现异常时 |
SendAsync | 服务端发送消息到客户端 |
Websocket功能接口的实现
public class WebSocketOperate : IWebSocketOperate
{
private HttpListener _httpListener;
public Action<WebSocketConnected, string> OnMessage {
get; set; }
public Action<WebSocketConnected> OnOpen {
get; set; }
public Action<WebSocketConnected> OnClose {
get; set; }
public Action<WebSocketConnected, string> OnError {
get; set; }
public WebSocketOperate(HttpListener httpListener, Action<IWebSocketOperate> initialize)
{
try
{
initialize(this);
_httpListener = httpListener;
_httpListener.Start();
Console.WriteLine($"Service on Running ws://{
httpListener.Prefixes.First().Replace("http://", string.Empty)}");
while (true)
{
HttpListenerContext ctx = _httpListener.GetContext();
ThreadPool.QueueUserWorkItem(new WaitCallback(TaskProc), ctx);
}
}
catch (Exception ex)
{
Console.WriteLine("服务异常:" + ex.ToString());
}
}
//用于保存连接数据
static List<WebSocketConnected> websContainer = new List<WebSocketConnected>();
public async void TaskProc(object ctx)
{
HttpListenerContext context = ctx as HttpListenerContext;
byte[] buf = new byte[1024];
ArraySegment<byte> abuf = new ArraySegment<byte>(buf);
CancellationToken cancel = CancellationToken.None;
HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null, TimeSpan.FromDays(1));
WebSocket ws = webSocketContext.WebSocket;
WebSocketConnected webConected = new WebSocketConnected {
RemoteEndPoint = context.Request.RemoteEndPoint, WebSocket = ws };
websContainer.Add(webConected);
OnOpen?.Invoke(webConected);
while (true)
{
if (ws.State == WebSocketState.CloseReceived)
{
OnClose?.Invoke(webConected);
websContainer.Remove(webConected);
ws.Abort();
ws.Dispose();
break;
}
try
{
var wsdata = await ws.ReceiveAsync(abuf, cancel);
byte[] bRec = new byte[wsdata.Count];
Array.Copy(buf, bRec, wsdata.Count);
OnMessage?.Invoke(webConected, Encoding.UTF8.GetString(bRec));
}
catch (Exception ex)
{
OnError?.Invoke(webConected, ex.Message);
ws.Dispose();
break;
}
}
}
public async void SendAsync(string text)
{
if (string.IsNullOrEmpty(text))
return;
byte[] bytes = Encoding.Default.GetBytes(text);
ArraySegment<byte> abuf = new ArraySegment<byte>(bytes);
CancellationToken cancel = CancellationToken.None;
foreach (var item in websContainer)
{
await item.WebSocket.SendAsync(abuf, WebSocketMessageType.Text, true, cancel);
}
}
public async void SendAsync(string text, WebSocketConnected connected)
{
if (string.IsNullOrEmpty(text) && connected != default(WebSocketConnected))
return;
byte[] bytes = Encoding.Default.GetBytes(text);
ArraySegment<byte> abuf = new ArraySegment<byte>(bytes);
CancellationToken cancel = CancellationToken.None;
await connected.WebSocket.SendAsync(abuf, WebSocketMessageType.Text, true, cancel);
}
}
入口文件
public class WebSocketService
{
private HttpListener httpListener;
public WebSocketService(string uriPrefix)
{
httpListener = new HttpListener();
httpListener.Prefixes.Add(uriPrefix);
}
public void Start(Action<IWebSocketOperate> webSockets)
{
WebSocketOperate operate = new WebSocketOperate(httpListener,webSockets);
}
}
程序的具体应用方法
static void Main(string[] argv)
{
WebSocketService ws = new WebSocketService("http://127.0.0.1:1500/");
ws.Start(socket =>
{
socket.OnOpen = (e) =>
{
Console.WriteLine($"| Open | {
e.RemoteEndPoint} | {
DateTime.Now} |");
};
socket.OnClose = (e) =>
{
Console.WriteLine($"| Close | {
e.RemoteEndPoint} | {
DateTime.Now} |");
};
socket.OnMessage = (e,msg) =>
{
if(msg == "GetDate")
{
socket.SendAsync(DateTime.Now.ToString(), e);
}
socket.SendAsync("Please Send GetDate!");
Console.WriteLine($"| Recv | {
e.RemoteEndPoint} | {
msg} | {
DateTime.Now} |");
};
socket.OnError = (e,msg) =>
{
Console.WriteLine($"| Error | {
e.RemoteEndPoint} | {
msg} | {
DateTime.Now} |");
};
});
}
你们的支持就是我创作的动力