WebSocket服务端 C#示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Text.RegularExpressions;
using System.Security.Cryptography; namespace WebSocketDemo
{
class Program
{
static void Main(string[] args)
{
int port = ;
byte[] buffer = new byte[]; IPEndPoint localEP = new IPEndPoint(IPAddress.Any, port);
Socket listener = new Socket(localEP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); try
{
listener.Bind(localEP);
listener.Listen(); Console.WriteLine("等待客户端连接....");
Socket sc = listener.Accept();//接受一个连接
Console.WriteLine("接受到了客户端:" + sc.RemoteEndPoint.ToString() + "连接...."); //握手
int length = sc.Receive(buffer);//接受客户端握手信息
sc.Send(PackHandShakeData(GetSecKeyAccetp(buffer, length)));
Console.WriteLine("已经发送握手协议了...."); //接受客户端数据
Console.WriteLine("等待客户端数据....");
length = sc.Receive(buffer);//接受客户端信息
string clientMsg = AnalyticData(buffer, length);
Console.WriteLine("接受到客户端数据:" + clientMsg); //发送数据
string sendMsg = "您好," + clientMsg;
Console.WriteLine("发送数据:“" + sendMsg + "” 至客户端....");
sc.Send(PackData(sendMsg)); Console.WriteLine("演示Over!"); }
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
/// <summary>
/// 打包握手信息
/// </summary>
/// <param name="secKeyAccept"></param>
/// <returns></returns>
private static byte[] PackHandShakeData(string secKeyAccept)
{
var responseBuilder = new StringBuilder();
responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine);
responseBuilder.Append("Upgrade: websocket" + Environment.NewLine);
responseBuilder.Append("Connection: Upgrade" + Environment.NewLine);
responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine + Environment.NewLine);
//如果把上一行换成下面两行,才是thewebsocketprotocol-17协议,但居然握手不成功,目前仍没弄明白!
//responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine);
//responseBuilder.Append("Sec-WebSocket-Protocol: chat" + Environment.NewLine); return Encoding.UTF8.GetBytes(responseBuilder.ToString());
} /// <summary>
/// 生成Sec-WebSocket-Accept
/// </summary>
/// <param name="handShakeText">客户端握手信息</param>
/// <returns>Sec-WebSocket-Accept</returns>
private static string GetSecKeyAccetp(byte[] handShakeBytes, int bytesLength)
{
string handShakeText = Encoding.UTF8.GetString(handShakeBytes, , bytesLength);
string key = string.Empty;
Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
Match m = r.Match(handShakeText);
if (m.Groups.Count != )
{
key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
}
byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
return Convert.ToBase64String(encryptionString);
} /// <summary>
/// 解析客户端数据包
/// </summary>
/// <param name="recBytes">服务器接收的数据包</param>
/// <param name="recByteLength">有效数据长度</param>
/// <returns></returns>
private static string AnalyticData(byte[] recBytes, int recByteLength)
{
if (recByteLength < ) { return string.Empty; } bool fin = (recBytes[] & 0x80) == 0x80; // 1bit,1表示最后一帧
if (!fin)
{
return string.Empty;// 超过一帧暂不处理
} bool mask_flag = (recBytes[] & 0x80) == 0x80; // 是否包含掩码
if (!mask_flag)
{
return string.Empty;// 不包含掩码的暂不处理
} int payload_len = recBytes[] & 0x7F; // 数据长度 byte[] masks = new byte[];
byte[] payload_data; if (payload_len == )
{
Array.Copy(recBytes, , masks, , );
payload_len = (UInt16)(recBytes[] << | recBytes[]);
payload_data = new byte[payload_len];
Array.Copy(recBytes, , payload_data, , payload_len); }
else if (payload_len == )
{
Array.Copy(recBytes, , masks, , );
byte[] uInt64Bytes = new byte[];
for (int i = ; i < ; i++)
{
uInt64Bytes[i] = recBytes[ - i];
}
UInt64 len = BitConverter.ToUInt64(uInt64Bytes, ); payload_data = new byte[len];
for (UInt64 i = ; i < len; i++)
{
payload_data[i] = recBytes[i + ];
}
}
else
{
Array.Copy(recBytes, , masks, , );
payload_data = new byte[payload_len];
Array.Copy(recBytes, , payload_data, , payload_len); } for (var i = ; i < payload_len; i++)
{
payload_data[i] = (byte)(payload_data[i] ^ masks[i % ]);
} return Encoding.UTF8.GetString(payload_data);
} /// <summary>
/// 打包服务器数据
/// </summary>
/// <param name="message">数据</param>
/// <returns>数据包</returns>
private static byte[] PackData(string message)
{
byte[] contentBytes = null;
byte[] temp = Encoding.UTF8.GetBytes(message); if (temp.Length < )
{
contentBytes = new byte[temp.Length + ];
contentBytes[] = 0x81;
contentBytes[] = (byte)temp.Length;
Array.Copy(temp, , contentBytes, , temp.Length);
}
else if (temp.Length < 0xFFFF)
{
contentBytes = new byte[temp.Length + ];
contentBytes[] = 0x81;
contentBytes[] = ;
contentBytes[] = (byte)(temp.Length & 0xFF);
contentBytes[] = (byte)(temp.Length >> & 0xFF);
Array.Copy(temp, , contentBytes, , temp.Length);
}
else
{
// 暂不处理超长内容
} return contentBytes;
}
}
}

HTML5 客户端示例代码

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebSockets客户端示例</title>
</head>
<script>
var webSocket;
function connect()
{
try
{
var readyState = new Array("正在连接","已建立连接","正在关闭连接","已关闭连接");
var host = "ws://localhost:10";
webSocket = new WebSocket(host);
var message = document.getElementById("message");
message.innerHTML +="<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
webSocket.onopen = function()
{
message.innerHTML += "<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
}
webSocket.onmessage = function(msg)
{
message.innerHTML +="<p>接收信息:" + msg.data + "</p>";
}
webSocket.onclose=function()
{
message.innerHTML +="<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
}
}
catch(exception)
{
message.innerHTML += "<p>有错误发生</p>";
}
}
function send()
{
var text = document.getElementById("text").value;
var message = document.getElementById("message");
if(text == "")
{
message.innerHTML += "<p>请输入一些文字</p>";
return ;
}
try
{
webSocket.send(text);
message.innerHTML += "<p>发送数据:" +text + "</p>";
}
catch(exception)
{
message.innerHTML += "<p>发送数据出错</p>";
}
document.getElementById("text").value="";
}
function disconnect()
{
webSocket.close();
}
</script>
<body>
<h1>WebSocket客户端示例</h1>
<div id="message"></div>
<p>请输入一些文字</p>
<input id="text" type="text">
<button id="connect" onClick="connect();">建立连接</button>
<button id="send" onClick="send();">发送数据</button>
<button id="disconnect" onClick="disconnect();">断开连接</button>
</body>
</html>

GitHub地址:BMBH/.NET-Demo

C# WebSocket 服务端示例代码 + HTML5客户端示例代码的更多相关文章

  1. 一文了解服务端推送(含JS代码示例)

    常用的服务端推送技术,包括轮询.长轮询.websocket.server-sent-event(SSE) 传统的HTTP请求是由客户端发送一个request,服务端返回对应response,所以当服务 ...

  2. 网络编程 UDP协议 TCP局域网客户端与服务端上传下载电影示例

    UDP协议 (了解) 称之为数据包协议,又称不可靠协议. 特点: 1) 不需要建立链接. 2) 不需要知道对方是否收到. 3) 数据不安全 4) 传输速度快 5)能支持并发 6) 不会粘包 7) 无需 ...

  3. asp.net网站作为websocket服务端的应用该如何写

    最近被websocket的一个问题困扰了很久,有一个需求是在web网站中搭建websocket服务.客户端通过网页与服务器建立连接,然后服务器根据ip给客户端网页发送信息. 其实,这个需求并不难,只是 ...

  4. Netty 搭建 WebSocket 服务端

    一.编码器.解码器 ... ... @Autowired private HttpRequestHandler httpRequestHandler; @Autowired private TextW ...

  5. nodejs搭建简单的websocket服务端

    创建websocket服务端使用了nodejs-websocket ,首先要安装nodejs-websocket,在项目的目录下: npm install nodejs-websocket 1.搭建w ...

  6. WebSocket服务端

    http://blog.csdn.net/qq_20282263/article/details/54310737 C# 实现WebSocket服务端 原创 2017年01月10日 09:22:50 ...

  7. 用nodejs快速实现websocket服务端(带SSL证书生成)

    有不少公司将nodejs的socket.io作为websocket的解决方案,很遗憾的是socket.io是对websocket的封装,并不支持html5原始的websocket协议,微信小程序使用的 ...

  8. SuperWebSocket实现服务端和WebSocket4Net实现客户端

    SuperWebSocket实现服务端和WebSocket4Net实现客户端具体实现如下: SuperWebSocket实现服务端 注:本作者是基于vs2019 enterprise版本,所有项目均为 ...

  9. git的CentOS服务端安装和windows客户端的使用

    git的CentOS服务端安装和windows客户端的使用 此教程以 搬瓦工vps CentOS 6 x64 的系统为环境,搭建 git 服务端.windows 7 系统为客户端. git客户端 在W ...

随机推荐

  1. Ubuntu 启动停止脚本

    /etc/init.d 目录下的开机启动脚本 1. more redis_8010 #/bin/sh #Configurations injected by install_server below. ...

  2. linux下IPTABLES配置

    如果你的IPTABLES基础知识还不了解,建议先去看看. 开始配置 我们来配置一个filter表的防火墙. (1)查看本机关于IPTABLES的设置情况 [root@tp ~]# iptables - ...

  3. 【转】移动Web单页应用开发实践——页面结构化

    1. 前言 在开发面向现代智能手机的移动Web应用的时候,无法避免一个事实,就是需要开发单页应用(Single Page WebApp).对于不同的系统需求,单页应用的粒度会不同,可能是整个系统都使用 ...

  4. CSS与JavaScript文件的位置

    1.CSS 尽量放置在head标签中. 原因: 避免浏览器重新渲染: 避免阻塞JS文件的执行. 注:CSS选择器的解释顺序是 从右向左 的,所以尽量减少选择器的层级. 2.JS 尽量放置在</b ...

  5. context:component-scan 分析

    <context:component-scan> Web.xml中 <servlet> <servlet-name>springMVC</servlet-na ...

  6. NV Maxwell architecture

    按照NVIDIA的路线图来看,GTX 600以及GTX 700系列所采用的Kepler架构已经垂垂老矣,最早在明年第一季度,其继任者Maxwell架构可能就会和我们正式见面了.目前外媒已经放出了关于M ...

  7. VC++6.0 显示行号

    通过VC6LineNumberAddin能够解决这个问题,方法如下. 一.下载该文件. 网上很多免费的. 二.使用方法:            [1]:打开VC++6.0,点击菜单“工具(Tools) ...

  8. PHP 开发 APP 接口 学习笔记与总结 - APP 接口实例 [3] 首页 APP 接口开发方案 ② 读取缓存方式

    以静态缓存为例. 修改 file.php line:11 去掉 path 参数(方便),加上缓存时间参数: public function cacheData($k,$v = '',$cacheTim ...

  9. spring对dao层的支持(datasource的作用)

    本文大多数内容转自“http://www.cnblogs.com/liunanjava/p/4412408.html”感谢原作者 在做一个项目时,持久层并没有使用spring jpa和hibernat ...

  10. 20145235 《Java程序设计》第8周学习总结

    教材学习内容总结 15.1.1日志API简介 使用日志的起点是logger类,logger实例的创建有许多要处理的要素,必须使用logger的静态方法getLogger(). 通常在哪个类上取得的lo ...