GVKun编程网logo

Golang实现基于Websocket协议的H5聊天室(golang websocket)

17

对于想了解Golang实现基于Websocket协议的H5聊天室的读者,本文将提供新的信息,我们将详细介绍golangwebsocket,并且为您提供关于.NETCore基于Websocket的在线聊

对于想了解Golang实现基于Websocket协议的H5聊天室的读者,本文将提供新的信息,我们将详细介绍golang websocket,并且为您提供关于.NET Core 基于Websocket的在线聊天室、.NET Core 基于Websocket的在线聊天室实现、C#基于WebSocket实现聊天室功能、express框架实现基于Websocket建立的简易聊天室的有价值信息。

本文目录一览:

Golang实现基于Websocket协议的H5聊天室(golang websocket)

Golang实现基于Websocket协议的H5聊天室(golang websocket)

http://www.cnblogs.com/wangrudong003/p/5535689.html

go代码部分:

// WebChat project main.go
package main

import (
	"fmt"
	"net/http"
	"time"

	"encoding/json"

	"strings"

	"golang.org/x/net/websocket"
)

//全局信息
var datas Datas
var users map[*websocket.Conn]string

func main() {
	fmt.Println("启动时间")
	fmt.Println(time.Now())

	//初始化
	datas = Datas{}
	users = make(map[*websocket.Conn]string)

	//绑定效果页面
	http.HandleFunc("/",h_index)
	//绑定socket方法
	http.Handle("/webSocket",websocket.Handler(h_webSocket))
	//开始监听
	http.ListenAndServe(":8080",nil)
}

func h_index(w http.ResponseWriter,r *http.Request) {

	http.ServeFile(w,r,"index.html")
}

func h_webSocket(ws *websocket.Conn) {

	var userMsg UserMsg
	var data string
	for {

		//判断是否重复连接
		if _,ok := users[ws]; !ok {
			users[ws] = "匿名"
		}
		userMsgsLen := len(datas.UserMsgs)
		fmt.Println("UserMsgs",userMsgsLen,"users长度:",len(users))

		//有消息时,全部分发送数据
		if userMsgsLen > 0 {
			b,errMarshl := json.Marshal(datas)
			if errMarshl != nil {
				fmt.Println("全局消息内容异常...")
				break
			}
			for key,_ := range users {
				errMarshl = websocket.Message.Send(key,string(b))
				if errMarshl != nil {
					//移除出错的链接
					delete(users,key)
					fmt.Println("发送出错...")
					break
				}
			}
			datas.UserMsgs = make([]UserMsg,0)
		}

		fmt.Println("开始解析数据...")
		err := websocket.Message.Receive(ws,&data)
		fmt.Println("data:",data)
		if err != nil {
			//移除出错的链接
			delete(users,ws)
			fmt.Println("接收出错...")
			break
		}

		data = strings.Replace(data,"\n","",0)
		err = json.Unmarshal([]byte(data),&userMsg)
		if err != nil {
			fmt.Println("解析数据异常...")
			break
		}
		fmt.Println("请求数据类型:",userMsg.DataType)

		switch userMsg.DataType {
		case "send":
			//赋值对应的昵称到ws
			if _,ok := users[ws]; ok {
				users[ws] = userMsg.UserName

				//清除连接人昵称信息
				datas.UserDatas = make([]UserData,0)
				//重新加载当前在线连接人
				for _,item := range users {

					userData := UserData{UserName: item}
					datas.UserDatas = append(datas.UserDatas,userData)
				}
			}
			datas.UserMsgs = append(datas.UserMsgs,userMsg)
		}
	}

}

type UserMsg struct {
	UserName string
	Msg      string
	DataType string
}

type UserData struct {
	UserName string
}

type Datas struct {
	UserMsgs  []UserMsg
	UserDatas []UserData
}

html5代码部分:(index.html 和main.go放置到同一目录)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title></title>
    <Meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
    <!-- 新 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
    <!--        <script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>-->
</head>
<body>
    <div>
        <div>内容:</div>
        <divid="divShow">
            <!--<div>1111</div>
            <div>1111</div>
            <div>1111</div>
            <div>1111</div>-->
        </div>
        <divid="divUsers">
            在线:<br />
            <!--<div>111</div>-->

        </div>
        <div>
            昵称:<inputid="txtUserName" value="红领巾" type="text" maxlength="20"https://www.jb51.cc/tag/ott/" target="_blank">ottom: 15px" />
            聊聊:<textareaid="txtContent" autofocus rows="6" placeholder="想聊的内容" maxlength="200" required></textarea>
            <buttonid="btnSend">发 送</button>
        </div>
    </div>
</body>
</html>

<script>

    var tool = function () {

        var paperLoopNum = 0;
        var paperTempleArr = [
            '<div>{0}</div>','<div>{0}</div>','<div>{0}</div>','<div>{0}</div>'
        ];

        return {

            paperDiv: function (val) {

                var hl = paperTempleArr[paperLoopNum];
                paperLoopNum++;
                if (paperLoopNum >= paperTempleArr.length) { paperLoopNum = 0; }

                return this.formart(hl,[val])
            },formart: function (str,arrVal) {

                for (var i = 0; i < arrVal.length; i++) {
                    str = str.replace("{" + i + "}",arrVal[i]);
                }
                return str;
            }
        }
    }

    function showMsg(id,hl,isAppend) {

        if (!isAppend) { $("#" + id).html(hl); } else {
            $("#" + id).append(hl);
        }
    }

    $(function () {

        //初始化工具方法
        var tl = new tool();

        var wsUrl = "ws://127.0.0.1:8080/webSocket";
        ws = new WebSocket(wsUrl);

        try {

            ws.onopen = function () {

                //showMsg("divShow",tl.paperDiv("连接服务器-成功"));
            }

            ws.onclose = function () {
                if (ws) {
                    ws.close();
                    ws = null;
                }
                showMsg("divShow",tl.paperDiv("连接服务器-关闭"),true);
            }

            ws.onmessage = function (result) {

                //console.log(result.data);
                var data = JSON.parse(result.data);
                $(data.UserMsgs).each(function (i,item) {
                    showMsg("divShow",tl.paperDiv("【" + item.UserName + "】:" + item.Msg),true);
                });

                var userDataShow = [];
                $(data.UserDatas).each(function (i,item) {

                    userDataShow.push('<div>' + item.UserName + '</div>');

                });
                showMsg("divUsers",userDataShow.join(''),false);
            }

            ws.onerror = function () {
                if (ws) {
                    ws.close();
                    ws = null;
                }
                showMsg("divShow",true);
            }

        } catch (e) {

            alert(e.message);
        }
        $("#btnSend").on("click",function () {

            var tContentObj = $("#txtContent");
            var tContent = $.trim( tContentObj.val()).replace("/[\n]/g","");
            var tUserName = $.trim( $("#txtUserName").val()); tUserName = tUserName.length <= 0 ? "匿名" : tUserName;
            if (tContent.length <= 0 || $.trim(tContent).length <= 0) { alert("请输入发送内容!"); return; }
            if (ws == null) { alert("连接失败,请F5刷新页面!"); return; }

            var request = tl.formart('{"UserName": "{0}","DataType": "{1}","Msg": "{2}" }',[tUserName,"send",tContent]);
            ws.send(request);
            tContentObj.val("");
            tContentObj.val($.trim(tContentObj.val()).replace("/[\n]/g",""));
        });
        $("#txtContent").on("keydown",function (event) {

            if (event.keyCode == 13) {

                $("#btnSend").trigger("click");
            }
        });
    })

</script>

效果图:

  

下载附件

.NET Core 基于Websocket的在线聊天室

.NET Core 基于Websocket的在线聊天室

什么是Websocket

我们在传统的客户端程序要实现实时双工通讯第一想到的技术就是socket通讯,但是在web体系是用不了socket通讯技术的,因为http被设计成无状态,每次跟服务器通讯完成后就会断开连接。
在没有websocket之前web系统如果要做双工通讯往往使用http long polling技术。http long polling 每次往服务器发送请求后,服务端不会立刻返回信息来结束请求,而是一直挂着直到有数据需要返回,或者等待超时了才会返回。客户端在结束上一次请求后立刻再发送一次请求,如此反复。http long polling虽然能实现web系统的双工通讯,但是有个很大的问题,就是基于http协议客户端每次发送请求都需要携带巨大的头部。在并发交互少量数据的时候非常不划算,对服务器资源的消耗也是巨大的。
websocket很好的改善了以上问题。它基于tcp重新设计了一套协议,同时又兼容http,默认跟http一样使用80/443端口。websocket链接建立本质上就是一次http请求,直接使用http协议的upgrade头来标识这是一次websocket请求,服务端回复101状态码表示“握手”成功。

//客户端请求
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13

//服务端响应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/

使用asp.net core来处理websocket

上面我们简单的了解了websocket,那么如何来使用asp.net core处理websocket呢?因为websocket的握手就是一次http请求,那么我们就可以使用一个middleware来拦截websocket的请求,把建立的链接统一进行管理,其实微软已经帮我们简单的封装过了。

新建一个asp.net core网站

新建WebsocketHandlerMiddleware中间件

这个中间件就是我们管理websocket链接的入口,我们调用context.WebSockets.AcceptWebSocketAsync()方法把请求转换为websocket链接。

在Invoke方法内接收websocket链接

      public async Task Invoke(HttpContext context)
        {
            if (context.Request.Path == "/ws")
            {
                if (context.WebSockets.IsWebSocketRequest)
                {
                    WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                    string clientId = Guid.NewGuid().ToString(); ;
                    var wsClient = new WebsocketClient
                    {
                        Id = clientId,
                        WebSocket = webSocket
                    };
                    try
                    {
                        await Handle(wsClient);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Echo websocket client {0} err .", clientId);
                        await context.Response.WriteAsync("closed");
                    }
                }
                else
                {
                    context.Response.StatusCode = 404;
                }
            }
            else
            {
                await _next(context);
            }
        }

在Hanle方法等待客户端的消息

        private async Task Handle(WebsocketClient webSocket)
        {
            WebsocketClientCollection.Add(webSocket);
            _logger.LogInformation($"Websocket client added.");
           
            WebSocketReceiveResult result = null;
            do
            {
                var buffer = new byte[1024 * 1];
                result = await webSocket.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                if (result.MessageType == WebSocketMessageType.Text && !result.CloseStatus.HasValue)
                {
                    var msgString = Encoding.UTF8.GetString(buffer);
                    _logger.LogInformation($"Websocket client ReceiveAsync message {msgString}.");
                    var message = JsonConvert.DeserializeObject<Message>(msgString);
                    message.SendClientId = webSocket.Id;
                    MessageRoute(message);
                }
            }
            while (!result.CloseStatus.HasValue);
            WebsocketClientCollection.Remove(webSocket);
            _logger.LogInformation($"Websocket client closed.");
        }

在MessageRoute方法内对客户端的消息进行转发

对客户端的消息定义几个标准的action,对不同的action进行特定的处理,比如加入房间、离开房间、在房间内广播消息等。

private void MessageRoute(Message message)
        {
            var client = WebsocketClientCollection.Get(message.SendClientId);
            switch (message.action)
            {
                case "join":
                    client.RoomNo = message.msg;
                    client.SendMessageAsync($"{message.nick} join room {client.RoomNo} success .");
                    _logger.LogInformation($"Websocket client {message.SendClientId} join room {client.RoomNo}.");
                    break;
                case "send_to_room":
                    if (string.IsNullOrEmpty(client.RoomNo))
                    {
                        break;
                    }
                    var clients = WebsocketClientCollection.GetRoomClients(client.RoomNo);
                    clients.ForEach(c =>
                    {
                        c.SendMessageAsync(message.nick + " : " + message.msg);
                    });
                    _logger.LogInformation($"Websocket client {message.SendClientId} send message {message.msg} to room {client.RoomNo}");

                    break;
                case "leave":
                    var roomNo = client.RoomNo;
                    client.RoomNo = "";
                    client.SendMessageAsync($"{message.nick} leave room {roomNo} success .");
                    _logger.LogInformation($"Websocket client {message.SendClientId} leave room {roomNo}");
                    break;
                default:
                    break;
            }
        }

新建WebsocketClientCollection管理类

这个类是个容器,用来存放所有的websocket链接,便于统一管理。

    public class WebsocketClientCollection
    {
        private static List<WebsocketClient> _clients = new List<WebsocketClient>();

        public static void Add(WebsocketClient client)
        {
            _clients.Add(client);
        }

        public static void Remove(WebsocketClient client)
        {
            _clients.Remove(client);
        }

        public static WebsocketClient Get(string clientId)
        {
            var client = _clients.FirstOrDefault(c=>c.Id == clientId);

            return client;
        }

        public static List<WebsocketClient> GetRoomClients(string roomNo)
        {
            var client = _clients.Where(c => c.RoomNo == roomNo);
            return client.ToList();
        }
    }

在Startup中使用中间件

有了上面的中间件,我们需要use一下。

  app.UseWebSockets(new WebSocketOptions
            {
                KeepAliveInterval = TimeSpan.FromSeconds(60),
                ReceiveBufferSize = 1* 1024
            });
  app.UseMiddleware<WebsocketHandlerMiddleware>();

到此我们的服务端基本完成了,下面进行客户端html跟JavaScript的编写。

编写客户端界面

修改index.cshtml来实现一个简单的聊天室ui。

<div>
    room no: <input type="text"  id="txtRoomNo" value="8888"/> <button id="btnJoin">join room</button> <button id="btnLeave">leave room</button>
</div>
<div>
    nick name: <input type="text" id="txtNickName" value="batman" /> 
</div>
<div>
    <textareaid="msgList"></textarea>
    <div>
        <input type="text" id="txtMsg" value="" />  <button id="btnSend">send</button>
    </div>
</div>

使用JavaScript来处理websocket链接及消息

现代浏览器已经都支持websocket协议,JavaScript运行时内置了WebSocket类,我们仅仅需要new一个Websocket对象出来就可以对websocket进行操作。


var server = ''ws://localhost:5000''; //如果开启了https则这里是wss

var WEB_SOCKET = new WebSocket(server + ''/ws'');

WEB_SOCKET.onopen = function (evt) {
    console.log(''Connection open ...'');
    $(''#msgList'').val(''websocket connection opened .'');
};

WEB_SOCKET.onmessage = function (evt) {
    console.log(''Received Message: '' + evt.data);
    if (evt.data) {
        var content = $(''#msgList'').val();
        content = content + ''\r\n'' + evt.data;

        $(''#msgList'').val(content);
    }
};

WEB_SOCKET.onclose = function (evt) {
    console.log(''Connection closed.'');
};

$(''#btnJoin'').on(''click'', function () {
    var roomNo = $(''#txtRoomNo'').val();
    var nick = $(''#txtNickName'').val();
    if (roomNo) {
        var msg = {
            action: ''join'',
            msg: roomNo,
            nick: nick
        };
        WEB_SOCKET.send(JSON.stringify(msg));
    }
});

$(''#btnSend'').on(''click'', function () {
    var message = $(''#txtMsg'').val();
    var nick = $(''#txtNickName'').val();
    if (message) {
        WEB_SOCKET.send(JSON.stringify({
            action: ''send_to_room'',
            msg: message,
            nick: nick
        }));
    }
});

$(''#btnLeave'').on(''click'', function () {
    var nick = $(''#txtNickName'').val();
    var msg = {
        action: ''leave'',
        msg: '''',
        nick: nick
    };
    WEB_SOCKET.send(JSON.stringify(msg));
});

运行

至此我们的聊天室已经搭建完成了,运行一下看看效果。我们启动两个页面,进行聊天。 可以看到我们的消息被实时的转发出去了,good job !

源码

源码已上传github CoreWebsocketChatRoom

原文出处:https://www.cnblogs.com/kklldog/p/core-for-websocket.html

.NET Core 基于Websocket的在线聊天室实现

.NET Core 基于Websocket的在线聊天室实现

什么是Websocket

我们在传统的客户端程序要实现实时双工通讯第一想到的技术就是socket通讯,但是在web体系是用不了socket通讯技术的,因为http被设计成无状态,每次跟服务器通讯完成后就会断开连接。

在没有websocket之前web系统如果要做双工通讯往往使用http long polling技术。http long polling 每次往服务器发送请求后,服务端不会立刻返回信息来结束请求,而是一直挂着直到有数据需要返回,或者等待超时了才会返回。客户端在结束上一次请求后立刻再发送一次请求,如此反复。http long polling虽然能实现web系统的双工通讯,但是有个很大的问题,就是基于http协议客户端每次发送请求都需要携带巨大的头部。在并发交互少量数据的时候非常不划算,对服务器资源的消耗也是巨大的。

websocket很好的改善了以上问题。它基于tcp重新设计了一套协议,同时又兼容http,默认跟http一样使用80/443端口。

websocket链接建立本质上就是一次http请求,直接使用http协议的upgrade头来标识这是一次websocket请求,服务端回复101状态码表示“握手”成功。

//客户端请求
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13

//服务端响应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/

使用asp.net core来处理websocket

上面我们简单的了解了websocket,那么如何来使用asp.net core处理websocket呢?因为websocket的握手就是一次http请求,那么我们就可以使用一个middleware来拦截websocket的请求,把建立的链接统一进行管理,其实微软已经帮我们简单的封装过了。

新建一个asp.net core网站

新建WebsocketHandlerMiddleware中间件

这个中间件就是我们管理websocket链接的入口,我们调用context.WebSockets.AcceptWebSocketAsync()方法把请求转换为websocket链接。

在Invoke方法内接收websocket链接

 public async Task Invoke(HttpContext context)
 {
  if (context.Request.Path == "/ws")
  {
  if (context.WebSockets.IsWebSocketRequest)
  {
   WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
   string clientId = Guid.NewGuid().ToString(); ;
   var wsClient = new WebsocketClient
   {
   Id = clientId,
   WebSocket = webSocket
   };
   try
   {
   await Handle(wsClient);
   }
   catch (Exception ex)
   {
   _logger.LogError(ex, "Echo websocket client {0} err .", clientId);
   await context.Response.WriteAsync("closed");
   }
  }
  else
  {
   context.Response.StatusCode = 404;
  }
  }
  else
  {
  await _next(context);
  }
 }

在Hanle方法等待客户端的消息

 private async Task Handle(WebsocketClient webSocket)
 {
  WebsocketClientCollection.Add(webSocket);
  _logger.LogInformation($"Websocket client added.");
  
  WebSocketReceiveResult result = null;
  do
  {
  var buffer = new byte[1024 * 1];
  result = await webSocket.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  if (result.MessageType == WebSocketMessageType.Text && !result.CloseStatus.HasValue)
  {
   var msgString = Encoding.UTF8.GetString(buffer);
   _logger.LogInformation($"Websocket client ReceiveAsync message {msgString}.");
   var message = JsonConvert.DeserializeObject<Message>(msgString);
   message.SendClientId = webSocket.Id;
   MessageRoute(message);
  }
  }
  while (!result.CloseStatus.HasValue);
  WebsocketClientCollection.Remove(webSocket);
  _logger.LogInformation($"Websocket client closed.");
 }

在MessageRoute方法内对客户端的消息进行转发

对客户端的消息定义几个标准的action,对不同的action进行特定的处理,比如加入房间、离开房间、在房间内广播消息等。

private void MessageRoute(Message message)
 {
  var client = WebsocketClientCollection.Get(message.SendClientId);
  switch (message.action)
  {
  case "join":
   client.RoomNo = message.msg;
   client.SendMessageAsync($"{message.nick} join room {client.RoomNo} success .");
   _logger.LogInformation($"Websocket client {message.SendClientId} join room {client.RoomNo}.");
   break;
  case "send_to_room":
   if (string.IsNullOrEmpty(client.RoomNo))
   {
   break;
   }
   var clients = WebsocketClientCollection.GetRoomClients(client.RoomNo);
   clients.ForEach(c =>
   {
   c.SendMessageAsync(message.nick + " : " + message.msg);
   });
   _logger.LogInformation($"Websocket client {message.SendClientId} send message {message.msg} to room {client.RoomNo}");

   break;
  case "leave":
   var roomNo = client.RoomNo;
   client.RoomNo = "";
   client.SendMessageAsync($"{message.nick} leave room {roomNo} success .");
   _logger.LogInformation($"Websocket client {message.SendClientId} leave room {roomNo}");
   break;
  default:
   break;
  }
 }

新建WebsocketClientCollection管理类

这个类是个容器,用来存放所有的websocket链接,便于统一管理。

 public class WebsocketClientCollection
 {
 private static List<WebsocketClient> _clients = new List<WebsocketClient>();

 public static void Add(WebsocketClient client)
 {
  _clients.Add(client);
 }

 public static void Remove(WebsocketClient client)
 {
  _clients.Remove(client);
 }

 public static WebsocketClient Get(string clientId)
 {
  var client = _clients.FirstOrDefault(c=>c.Id == clientId);

  return client;
 }

 public static List<WebsocketClient> GetRoomClients(string roomNo)
 {
  var client = _clients.Where(c => c.RoomNo == roomNo);
  return client.ToList();
 }
 }

在Startup中使用中间件

有了上面的中间件,我们需要use一下。

 app.UseWebSockets(new WebSocketOptions
  {
  KeepAliveInterval = TimeSpan.FromSeconds(60),
  ReceiveBufferSize = 1* 1024
  });
 app.UseMiddleware<WebsocketHandlerMiddleware>();

到此我们的服务端基本完成了,下面进行客户端html跟JavaScript的编写。

编写客户端界面

修改index.cshtml来实现一个简单的聊天室ui。

<div>
 room no: <input type="text" id="txtRoomNo" value="8888"/> <button id="btnJoin">join room</button> <button id="btnLeave">leave room</button>
</div>
<div>
 nick name: <input type="text" id="txtNickName" value="batman" /> 
</div>
<div>
 <textareaid="msgList"></textarea>
 <div>
 <input type="text" id="txtMsg" value="" /> <button id="btnSend">send</button>
 </div>
</div>

使用JavaScript来处理websocket链接及消息

现代浏览器已经都支持websocket协议,JavaScript运行时内置了WebSocket类,我们仅仅需要new一个Websocket对象出来就可以对websocket进行操作。

var server = ''ws://localhost:5000''; //如果开启了https则这里是wss

var WEB_SOCKET = new WebSocket(server + ''/ws'');

WEB_SOCKET.onopen = function (evt) {
 console.log(''Connection open ...'');
 $(''#msgList'').val(''websocket connection opened .'');
};

WEB_SOCKET.onmessage = function (evt) {
 console.log(''Received Message: '' + evt.data);
 if (evt.data) {
 var content = $(''#msgList'').val();
 content = content + ''\r\n'' + evt.data;

 $(''#msgList'').val(content);
 }
};

WEB_SOCKET.onclose = function (evt) {
 console.log(''Connection closed.'');
};

$(''#btnJoin'').on(''click'', function () {
 var roomNo = $(''#txtRoomNo'').val();
 var nick = $(''#txtNickName'').val();
 if (roomNo) {
 var msg = {
  action: ''join'',
  msg: roomNo,
  nick: nick
 };
 WEB_SOCKET.send(JSON.stringify(msg));
 }
});

$(''#btnSend'').on(''click'', function () {
 var message = $(''#txtMsg'').val();
 var nick = $(''#txtNickName'').val();
 if (message) {
 WEB_SOCKET.send(JSON.stringify({
  action: ''send_to_room'',
  msg: message,
  nick: nick
 }));
 }
});

$(''#btnLeave'').on(''click'', function () {
 var nick = $(''#txtNickName'').val();
 var msg = {
 action: ''leave'',
 msg: '''',
 nick: nick
 };
 WEB_SOCKET.send(JSON.stringify(msg));
});

运行

至此我们的聊天室已经搭建完成了,运行一下看看效果。我们启动两个页面,进行聊天。
可以看到我们的消息被实时的转发出去了,good job !


源码

源码已上传github
CoreWebsocketChatRoom

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

您可能感兴趣的文章:
  • Asp.net Core中如何使用中间件来管理websocket
  • Asp.Net Core中WebSocket绑定的方法详解
  • NetCore WebSocket即时通讯示例
  • 在Asp.net core中实现websocket通信

C#基于WebSocket实现聊天室功能

C#基于WebSocket实现聊天室功能

本文实例为大家分享了C#基于WebSocket实现聊天室功能的具体代码,供大家参考,具体内容如下

前面两篇温习了,C# Socket内容

本章根据Socket异步聊天室修改成WebSocket聊天室

WebSocket特别的地方是 握手和消息内容的编码、解码(添加了ServerHelper协助处理)

ServerHelper:

using System;
using System.Collections;
using System.Text;
using System.Security.Cryptography;
 
namespace SocketDemo
{
    // Server助手 负责:1 握手 2 请求转换 3 响应转换
    class ServerHelper
    {
        /// <summary>
        /// 输出连接头信息
        /// </summary>
        public static string ResponseHeader(string requestHeader)
        {
            Hashtable table = new Hashtable();
 
            // 拆分成键值对,保存到哈希表
            string[] rows = requestHeader.Split(new string[] { "\r\n" }, 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\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);
 
            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\n", Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + magic))));
 
            header.Append("\r\n");
 
            return header.ToString();
        }
 
        /// <summary>
        /// 解码请求内容
        /// </summary>
        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);
        }
 
        /// <summary>
        /// 编码响应内容
        /// </summary>
        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<ClientInfo> clientList = new List<ClientInfo>();
        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:

<!DOCTYPE html>
<script>
    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;
    }
</script>
<html>
<head>
    <title></title>
</head>
<body>
    <div id="roomContent">
    </div>
    <div>
        <textarea id="content" cols="50" rows="3"></textarea>
    </div>
    <input type="button" value="Connection" οnclick="Star()" />
    <input type="button" value="Send" οnclick="Send()" />
</body>
</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

您可能感兴趣的文章:
  • C#用websocket实现简易聊天功能(客户端)
  • C#用websocket实现简易聊天功能(服务端)
  • C#使用WebSocket实现聊天室功能
  • C# 实现WebSocket服务端教程
  • C# websocket及时通信协议的实现方法示例
  • C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析
  • C# Websocket连接实现wss协议

express框架实现基于Websocket建立的简易聊天室

express框架实现基于Websocket建立的简易聊天室

最近想写点有意思的,所以整了个这个简单的不太美观的小玩意

首先你得确认你的电脑装了node,然后就可以按照步骤 搞事情了~~

1.建立一个文件夹

2.清空当前文件夹地址栏,在文件夹地址栏中输入cmd.exe

3.我们需要下载点小东西 ,需要在命令行输入

  • npm install express 回车 等待一会
  • npm install express-session 回车 等待一会
  • npm install ejs 回车 等待一会
  • npm install socket.io 回车 等待一会 叮~~~ 搞定!!!

4.安装完成后,在你建的文件夹下 就会有一个 node_modules文件夹,接下来我们还需要建立俩文件夹,一个文件夹(public)存放静态资源,并且添加jquery文件,一个文件夹(views)存放静态模板ejs文件。

5.接下来我们就需要建立一个入口文件(app.js),在你建立的文件夹下 。

6.app.js中必须写的

var express=require(''express'');
var app=express();


//加载express web server
var http=require(''http'').Server(app);
//加载websocket server-->http://localhost:3000/socket.io/socket.io.js
var io=require(''socket.io'')(http);
//监听端口3000
http.listen(3000);

7.(1)加载路由、处理路由、配置ejs模板、处理静态资源管理器

app.get app.post
app.set("view engine","ejs");
app.use(express.static(''./public''));

(2)建立俩文件,index.ejs、chat.ejs,在chat.ejs下我们需要引入

<script src="/socket.io/socket.io.js"></script>
<script src="/jquery-1.12.4.js"></script>

如果你本地没有的话,你可以这样玩~~

咱可以引用在线的嘛(亲测好使)

<script src="http://code.jquery.com/jquery-latest.js"></script>

8.app.get 路由 action=‘check''

判断登陆的三个条件

1-不能为空

2-不能重名

3-注册并且跳转chat页面

9.咱登陆了,要聊天,咱得告诉别人咱叫啥啊!!!所以这里需要处理session了,并且在chat页面显示出来嘛

10.所以咱得开始建立websocket通讯了

client

<script src="/socket.io/socket.io.js"></script>
<script src="/jquery-1.12.4.js"></script>

<script>
   var socket=io();

   socke.emit(''事件名'',''数据''); 数据可以是对象(登陆者和内容)
</script>

server

 io.on(''connection'',function(socket){
  socket.on(''事件名'',function(data){

    io.emit(''新的事件名'',data);
  });
});

client

socket.on(''新的事件名'',function(msg){
     dom操作  把msg数据渲染给我们的dom结构
})

基本的思路和步骤就是这些

现在一切工作准备就绪,开始码代码

app.js

var express=require(''express'');
var app=express();
var http=require(''http'').Server(app);
var io=require(''socket.io'')(http);

var session=require(''express-session'');
app.use(session({
 secret: ''keyboard cat'',
 resave: false,
 saveUninitialized: true,
 //cookie: { secure: true }
}));

//模板引擎
app.set("view engine","ejs");
//静态服务
app.use(express.static(''./public''));

var alluser=[];
//中间件
//显示首页
app.get(''/'',function(req,res,next){
  res.render(''index'');
});

//确认登录,检查此人是否有用户名 昵称不能重复
app.get(''/check'',function(req,res,next){
  var yonghuming=req.query.yonghuming;

  if(!yonghuming){
    res.send(''必须填写用户名'');
    return;
  }

  if(alluser.indexOf(yonghuming) != -1){
    res.send(''用户名重名'');
    return;
  }

  alluser.push(yonghuming);

  console.log(alluser);

  req.session.yonghuming=yonghuming;
  res.redirect("/chat");
});

//聊天室
app.get(''/chat'',function(req,res,next){
  //console.log(req.session.yonghuming);
  //console.log(123);
  if(!req.session.yonghuming){
    res.redirect("/");
    return;
  }
  res.render(''chat'',{
    ''yonghuming'':req.session.yonghuming
  });
});

io.on(''connection'',function(socket){
  socket.on(''liaotian'',function(msg){
    console.log(msg);
    //io.emit(''liaotian'',msg);
    //console.log(io);
    io.emit(''liaotian'',msg);
  });
})

//监听端口
http.listen(3000);
console.log(''server start port 3000'');

index.ejs(放views文件夹下)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    div{
      width:700px;
      height:30px;
      padding:40px;
      border:1px solid #000;
      margin:0 auto;
    }
    #yonghuming{
      font-size:30px;
    }
  </style>
</head>
<body>
  <div>
    <form action="/check" method="get">
    输入昵称:
    <input type="text" id="yonghuming" name="yonghuming">
    <input type="submit" value="进入聊天室">
    </form>
  </div>
</body>
</html>

chat.ejs

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <title>Document</title>
  <style>
    .caozuo{
      position:fixed;
      bottom:0;
      left:0;
      height:100px;
      background-color:#eee;
      width:100%;
    }
    .caozuo input{
      font-size:30px;
    }
    .caozuo input[type=text]{
      width:100%;
    }
  </style>
</head>
<body>
  <h1>Edison聊天室<span id="yonghu"> 欢迎:<%=yonghuming %></span></h1>
  <div>
    <ul></ul>
  </div>
  <div>
  <input type="text" id="neirong"/>
  <input type="button" id="fayan" value="发言"/>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script src="/jquery-1.12.4.min.js"></script>
  <script>
    var socket=io();
    $(''#neirong'').keydown(function(e){
      if(e.keyCode==13){
            //回车发送消息
        socket.emit(''liaotian'',{
          ''neirong'':$(''#neirong'').val(),
          ''ren'':$(''#yonghu'').html(),
        });
        $(this).val('''');
      }


    });

    /*
    $("#fayan").click(function(){
       //点击发言按钮发送消息
      socket.emit(''liaotian'',{
        ''neirong'':$(''#neirong'').val(),
        ''ren'':$(''#yonghu'').html(),
      });
    });*/

    socket.on(''liaotian'',function(msg){
      $(".liebiao").prepend("<li><b>"+msg.ren+": </b>"+msg.neirong+"</li>");
    });
  </script>
</body>
</html>


聊天室登陆界面


edison进入聊天室


edison与chan聊天

在码代码过程中,不断的踩坑,填坑,第一次整这玩意,很多地方不熟悉,难免有些错误,毕竟学习过程嘛,有点磕碜,如果你们也写了好使了,咱可以共同进步一起美化,完善更多的功能,忘各位old铁见谅~~~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

您可能感兴趣的文章:
  • node.js基于express使用websocket的方法
  • express中创建 websocket 接口及问题解答

关于Golang实现基于Websocket协议的H5聊天室golang websocket的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于.NET Core 基于Websocket的在线聊天室、.NET Core 基于Websocket的在线聊天室实现、C#基于WebSocket实现聊天室功能、express框架实现基于Websocket建立的简易聊天室等相关知识的信息别忘了在本站进行查找喔。

本文标签: