即时通信常用手段

1.第三方平台 谷歌、腾讯 环信等多如牛毛,其中谷歌即时通信是免费的,但免费就是免费的并不好用。其他的一些第三方一般收费的,使用要则限流(1s/限制x条消息)要么则限制用户数。
但稳定性什么都还不错,又能将服务压力甩出
2.System.Net.Sockets.Socket,也能写一套较好的服务器端。在.NET 4.5之前用较多,使用起来麻烦。需要对数据包进行解析等操作(但貌似网上有对超长包的处理方法)
3.System.Net.WebSockets.WebSocket,这个,是.NET 4.5出来的东西,对服务器环境也有所要求,IIS8及以上。意味着Windows Server2008R2自带的IIS不支持,Windows8及Server2012以上自带的IIS可以。本文主要将这种方式的实例
完整流程
1).客户端请求连接
复制代码 代码如下:
ws = new WebSocket('ws://' + window.location.hostname + ':' + window.location.port + '/Handler1.ashx?user=' + $("#user").val());
2).服务端获取连接对象并存储到连接池中
CONNECT_POOL.Add(user, socket);
3).连接对象开始监听(每个客户端与服务器保存长链接)
复制代码 代码如下:
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
4).客户端A发送消息给B
ws.send($("#to").val() + "|" + $('#content').val());
5).服务端A的连接对象监听到来自A的消息
string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
6).解析消息体(B|你好我是A)得到接收者ID,根据接收者ID到连接池中查找B的服务端连接对象,并通过B的连接对象将消息推送给B客户端
WebSocket destSocket = CONNECT_POOL[descUser]; await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
7).服务端A连接对象继续监听
复制代码 代码如下:
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
8).B客户端接收到推送过来的消息
ws.onmessage = function (evt) {
$('#msg').append('<p>' + evt.data + '</p>');
}
下面则是完整代码
客户端部分
客户端异常简单,正常情况直接用WebSocket,然后监听WebSocket的几个事件就ok。连接的时候可将当前连接者的ID传入(用户编号),发送消息的时候 采用 “接收者ID|我是消息内容” 这种方式,如“A|A你好,我是B!”
但如用移动端使用还是有一些常见的场景需要处理下的
1:手机关屏幕,IOS关掉屏幕的时候WebSocket会立即失去连接,Android则会等待一段时间才会失去连接。服务器端能检测到失去连接
2:网络不稳定,断网情况WebSocket也不会立即失去连接,服务器端不能知道。(可以服务端设计心跳机制,定时给连接池中的用户发送消息,来检测用户是否保持连接)
3:其他等等...(突然关机、后台结束应用)
无论哪种,客户端在发送消息(或者网络恢复连接、亮屏)的时候可以先判断ws的状态,如果不是连接状态则需要重连(new下即可)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<title></title>
<script src="jquery-1.11.3.min.js"></script>
<script>
var ws;
$().ready(function () {
$('#conn').click(function () {
ws = new WebSocket('ws://' + window.location.hostname + ':' + window.location.port + '/Handler1.ashx?user=' + $("#user").val());
$('#msg').append('<p>正在连接</p>');
ws.onopen = function () {
$('#msg').append('<p>已经连接</p>');
}
ws.onmessage = function (evt) {
$('#msg').append('<p>' + evt.data + '</p>');
}
ws.onerror = function (evt) {
$('#msg').append('<p>' + JSON.stringify(evt) + '</p>');
}
ws.onclose = function () {
$('#msg').append('<p>已经关闭</p>');
}
});
$('#close').click(function () {
ws.close();
});
$('#send').click(function () {
if (ws.readyState == WebSocket.OPEN) {
ws.send($("#to").val() + "|" + $('#content').val());
}
else {
$('#tips').text('连接已经关闭');
}
});
});
</script>
</head>
<body>
<div>
<input id="user" type="text" />
<input id="conn" type="button" value="连接" />
<input id="close" type="button" value="关闭"/><br />
<span id="tips"></span>
<input id="content" type="text" />
<input id="send" type="button" value="发送"/><br />
<input id="to" type="text" />目的用户
<div id="msg">
</div>
</div>
</body>
</html>
服务器端部分
服务器端使用Handler(也可用WebAPI)来做,主要用WebSocket的类来实现。代码中都有相对详细的注释,这边只说一些需要注意的问题
1:Dictionary<string,WebSocket> CONNECT_POOL:用户连接池。请求Handler的时候会将当前连接者的用户ID传入,服务器端维护着所有已连接的用户ID和当前用户的WebSocket连接对象
2:Dictionary<string,List<MessageInfo>> MESSAGE_POOL:离线消息池。如果A->B发送消息,B当前因为某种原因没在线(突然断网/黑屏等原因),会将这条消息先保存起来(2天),待B连接后立马将B的离线消息推送给他。(2:MessageInfo:离线Entity。记录当前离线消息的时间、内容)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.WebSockets;
namespace WebApplication1
{
/// <summary>
/// 离线消息
/// </summary>
public class MessageInfo
{
public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
{
MsgTime = _MsgTime;
MsgContent = _MsgContent;
}
public DateTime MsgTime { get; set; }
public ArraySegment<byte> MsgContent { get; set; }
}
/// <summary>
/// Handler1 的摘要说明
/// </summary>
public class Handler1 : IHttpHandler
{
private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
context.AcceptWebSocketRequest(ProcessChat);
}
}
private async Task ProcessChat(AspNetWebSocketContext context)
{
WebSocket socket = context.WebSocket;
string user = context.QueryString["user"].ToString();
try
{
#region 用户添加连接池
//第一次open时,添加到连接池中
if (!CONNECT_POOL.ContainsKey(user))
CONNECT_POOL.Add(user, socket);//不存在,添加
else
if (socket != CONNECT_POOL[user])//当前对象不一致,更新
CONNECT_POOL[user] = socket;
#endregion
#region 离线消息处理
if (MESSAGE_POOL.ContainsKey(user))
{
List<MessageInfo> msgs = MESSAGE_POOL[user];
foreach (MessageInfo item in msgs)
{
await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
}
MESSAGE_POOL.Remove(user);//移除离线消息
}
#endregion
string descUser = string.Empty;//目的用户
while (true)
{
if (socket.State == WebSocketState.Open)
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
#region 消息处理(字符截取、消息转发)
try
{
#region 关闭Socket处理,删除连接池
if (socket.State != WebSocketState.Open)//连接关闭
{
if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
break;
}
#endregion
string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
string[] msgList = userMsg.Split('|');
if (msgList.Length == 2)
{
if (msgList[0].Trim().Length > 0)
descUser = msgList[0].Trim();//记录消息目的用户
buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
}
else
buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
{
WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
if (destSocket != null && destSocket.State == WebSocketState.Open)
await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
else
{
Task.Run(() =>
{
if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
});
}
}
catch (Exception exs)
{
//消息转发异常处理,本次消息忽略 继续监听接下来的消息
}
#endregion
}
else
{
break;
}
}//while end
}
catch (Exception ex)
{
//整体异常处理
if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# asp.net
# 即时通讯
# c#
# websocket即时通信
# websocket实例
# .Net使用SuperSocket框架实现WebSocket后端
# .NET Core 基于Websocket的在线聊天室实现
# Asp.net Core中如何使用中间件来管理websocket
# Asp.Net Core中WebSocket绑定的方法详解
# .Net使用SuperSocket框架实现WebSocket前端
# 离线
# 客户端
# 服务端
# 我是
# 池中
# 发送消息
# 连接池
# 自带
# 第三方
# 会将
# 即时通信
# 断网
# 你好
# 几个
# 都有
# 给他
# 多如牛毛
# 则是
# 才会
# 也能
相关文章:
太原网站制作公司有哪些,网约车营运证查询官网?
如何在Tomcat中配置并部署网站项目?
建站之星Pro快速搭建教程:模板选择与功能配置指南
如何通过.red域名打造高辨识度品牌网站?
网站制作模板下载什么软件,ppt模板免费下载网站?
巅云智能建站系统:可视化拖拽+多端适配+免费模板一键生成
如何快速搭建高效香港服务器网站?
如何选择可靠的免备案建站服务器?
如何将凡科建站内容保存为本地文件?
建站之星后台密码遗忘如何找回?
青岛网站设计制作公司,查询青岛招聘信息的网站有哪些?
如何在Ubuntu系统下快速搭建WordPress个人网站?
,网页ppt怎么弄成自己的ppt?
零服务器AI建站解决方案:快速部署与云端平台低成本实践
安徽网站建设与外贸建站服务专业定制方案
厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?
,柠檬视频怎样兑换vip?
无锡营销型网站制作公司,无锡网选车牌流程?
如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?
单页制作网站有哪些,朋友给我发了一个单页网站,我应该怎么修改才能把他变成自己的呢,请求高手指点迷津?
焦点电影公司作品,电影焦点结局是什么?
学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?
ppt在线制作免费网站推荐,有什么下载免费的ppt模板网站?
如何在建站宝盒中设置产品搜索功能?
如何在服务器上配置二级域名建站?
Java解压缩zip - 解压缩多个文件或文件夹实例
建站之星伪静态规则如何正确配置?
宝塔面板创建网站无法访问?如何快速排查修复?
网站规划与制作是什么,电子商务网站系统规划的内容及步骤是什么?
做企业网站制作流程,企业网站制作基本流程有哪些?
香港服务器网站推广:SEO优化与外贸独立站搭建策略
建站ABC备案流程中有哪些关键注意事项?
制作网页的网站有哪些,电脑上怎么做网页?
个人网站制作流程图片大全,个人网站如何注销?
定制建站如何定义?其核心优势是什么?
建站之星安装后如何自定义网站颜色与字体?
我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?
如何在阿里云部署织梦网站?
高性能网站服务器配置指南:安全稳定与高效建站核心方案
建站之星24小时客服电话如何获取?
Avalonia如何实现跨窗口通信 Avalonia窗口间数据传递
表情包在线制作网站免费,表情包怎么弄?
利用JavaScript实现拖拽改变元素大小
如何用y主机助手快速搭建网站?
如何快速建站并高效导出源代码?
如何续费美橙建站之星域名及服务?
如何用PHP快速搭建CMS系统?
如何高效生成建站之星成品网站源码?
如何通过FTP服务器快速搭建网站?
详解jQuery中基本的动画方法
*请认真填写需求信息,我们会在24小时内与您取得联系。