阅读 232

NetCore WebSocket 即时通讯示例

1.新建Netcore Web项目

2.创建简易通讯协议

public class MsgTemplate
    {
        public string SenderID { get; set; }
        public string ReceiverID { get; set; }
        public string MessageType { get; set; }
        public string Content { get; set; }
    }复制代码

SenderID发送者ID

ReceiverID 接受者ID

MessageType 消息类型 Text Voice 等等

Content 消息内容

3.添加中间件ChatWebSocketMiddleware

  1 public class ChatWebSocketMiddleware
  2     {
  3         private static ConcurrentDictionary<string, System.Net.WebSockets.WebSocket> _sockets = new ConcurrentDictionary<string, System.Net.WebSockets.WebSocket>();
  4 
  5         private readonly RequestDelegate _next;
  6 
  7         public ChatWebSocketMiddleware(RequestDelegate next)
  8         {
  9             _next = next;
 10         }
 11 
 12         public async Task Invoke(HttpContext context)
 13         {
 14             if (!context.WebSockets.IsWebSocketRequest)
 15             {
 16                 await _next.Invoke(context);
 17                 return;
 18             }
 19             System.Net.WebSockets.WebSocket dummy;
 20 
 21             CancellationToken ct = context.RequestAborted;
 22             var currentSocket = await context.WebSockets.AcceptWebSocketAsync();
 23             //string socketId = Guid.NewGuid().ToString();
 24             string socketId = context.Request.Query["sid"].ToString();
 25             if (!_sockets.ContainsKey(socketId))
 26             {
 27                 _sockets.TryAdd(socketId, currentSocket);
 28             }
 29             //_sockets.TryRemove(socketId, out dummy);
 30             //_sockets.TryAdd(socketId, currentSocket);
 31 
 32             while (true)
 33             {
 34                 if (ct.IsCancellationRequested)
 35                 {
 36                     break;
 37                 }
 38 
 39                 string response = await ReceiveStringAsync(currentSocket, ct);
 40                 MsgTemplate msg = JsonConvert.DeserializeObject<MsgTemplate>(response);
 41 
 42                 if (string.IsNullOrEmpty(response))
 43                 {
 44                     if (currentSocket.State != WebSocketState.Open)
 45                     {
 46                         break;
 47                     }
 48 
 49                     continue;
 50                 }
 51 
 52                 foreach (var socket in _sockets)
 53                 {
 54                     if (socket.Value.State != WebSocketState.Open)
 55                     {
 56                         continue;
 57                     }
 58                     if (socket.Key == msg.ReceiverID || socket.Key == socketId)
 59                     {
 60                         await SendStringAsync(socket.Value, JsonConvert.SerializeObject(msg), ct);
 61                     }
 62                 }
 63             }
 64 
 65             //_sockets.TryRemove(socketId, out dummy);
 66 
 67             await currentSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", ct);
 68             currentSocket.Dispose();
 69         }
 70 
 71         private static Task SendStringAsync(System.Net.WebSockets.WebSocket socket, string data, CancellationToken ct = default(CancellationToken))
 72         {
 73             var buffer = Encoding.UTF8.GetBytes(data);
 74             var segment = new ArraySegment<byte>(buffer);
 75             return socket.SendAsync(segment, WebSocketMessageType.Text, true, ct);
 76         }
 77 
 78         private static async Task<string> ReceiveStringAsync(System.Net.WebSockets.WebSocket socket, CancellationToken ct = default(CancellationToken))
 79         {
 80             var buffer = new ArraySegment<byte>(new byte[8192]);
 81             using (var ms = new MemoryStream())
 82             {
 83                 WebSocketReceiveResult result;
 84                 do
 85                 {
 86                     ct.ThrowIfCancellationRequested();
 87 
 88                     result = await socket.ReceiveAsync(buffer, ct);
 89                     ms.Write(buffer.Array, buffer.Offset, result.Count);
 90                 }
 91                 while (!result.EndOfMessage);
 92 
 93                 ms.Seek(0, SeekOrigin.Begin);
 94                 if (result.MessageType != WebSocketMessageType.Text)
 95                 {
 96                     return null;
 97                 }
 98 
 99                 using (var reader = new StreamReader(ms, Encoding.UTF8))
100                 {
101                     return await reader.ReadToEndAsync();
102                 }
103             }
104         }
105     }复制代码

控制只有接收者才能收到消息
if (socket.Key == msg.ReceiverID || socket.Key == socketId)
{
     await SendStringAsync(socket.Value,JsonConvert.SerializeObject(msg), ct);
}复制代码

4.在Startup.cs中使用中间件

app.UseWebSockets();
app.UseMiddleware<ChatWebSocketMiddleware>();复制代码

5.建立移动端测试示例 这里采用Ionic3运行在web端

创建ionic3项目略过 新手可点这里查看 或者有Angular2/4项目经验的可直接往下看

(1) 启动Ionic项目

当初创建ionic3项目时候遇到不少问题

比如ionic-cli初始化项目失败 切换到默认npmorg源就好了

比如ionic serve失败 打开代理允许翻墙就好了

启动后界面是这样式的

(2) 创建聊天窗口dialog 具体布局实现 模块加载略过 直接进入websocket实现

在这之前别忘了启动web项目 否则会出现这样情况 链接不到服务

(3)dialog.ts具体实现

export class Dialog {

    private ws: any;
    private msgArr: Array<any>;

    constructor(private httpService: HttpService) {

        this.msgArr = [];
    }

    ionViewDidEnter() {
        if (!this.ws) {
            this.ws = new WebSocket("ws://localhost:56892?sid=222");

            this.ws.onopen = () => {
                console.log('open');
            };

            this.ws.onmessage = (event) => {
                console.log('new message: ' + event.data);
                var msgObj = JSON.parse(event.data);
                this.msgArr.push(msgObj);;
            };

            this.ws.onerror = () => {
                console.log('error occurred!');
            };

            this.ws.onclose = (event) => {
                console.log('close code=' + event.code);
            };
        }
    }

    sendMsg(msg) {//msg为我要发送的内容 比如"hello world"
        var msgObj = {
            SenderID: "222",
            ReceiverID: "111",
            MessageType: "text",
            Content: msg
        };
        this.ws.send(JSON.stringify(msgObj));
    }复制代码
ws://localhost:56892?sid=222 这是websocke服务链接地址
sid表示着我这个端的WebSocke唯一标识 找到这个key就可以找到我这个用户端了
6.在web端也实现一个会话窗口
<div class="container" style="width:90%;margin:0px auto;border:1px solid steelblue;">
    <div class="msg">
        <div id="msgs" style="height:200px;"></div>
    </div>

    <div style="display:block;width:100%">
        <input type="text" style="max-width:unset;width:100%;max-width:100%" id="MessageField" placeholder="type message and press enter" />
    </div>
</div>复制代码
<script>
        $(function () {
            $('.navbar-default').addClass('on');

            var userName = '@Model';

            var protocol = location.protocol === "https:" ? "wss:" : "ws:";
            var wsUri = protocol + "//" + window.location.host + "?sid=111";
            var socket = new WebSocket(wsUri);
            socket.onopen = e => {
                console.log("socket opened", e);
            };

            socket.onclose = function (e) {
                console.log("socket closed", e);
            };

            socket.onmessage = function (e) {
                console.log(e);
                var msgObj = JSON.parse(e.data);
                $('#msgs').append(msgObj.Content + '<br />');
            };

            socket.onerror = function (e) {
                console.error(e.data);
            };

            $('#MessageField').keypress(function (e) {
                if (e.which != 13) {
                    return;
                }

                e.preventDefault();

                var message = $('#MessageField').val();

                var msgObj = {
                    SenderID:"111",
                    ReceiverID:"222",
                    MessageType: "text",
                    Content: message
                };
                socket.send(JSON.stringify(msgObj));
                $('#MessageField').val('');
            });
        });
    </script>复制代码

基本开发完成 接下来看看效果

7.web和webapp端对话

8.webapp发送 web接收

9.目前就实现了这么多 因为项目还涉及其它技术 暂时不开放源码了 


关注下面的标签,发现更多相似文章
评论