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模拟发送接收的更多相关文章

  1. C# Socket模拟发送接收

    Socket简介 通过TCP/IP与仪器或设备通讯,在C#语言中,我们通常采用Socket.本项目是一个简单的Socket建立服务监听与Socket作为客户端请求的一个示例. 项目结构 客户端项目 S ...

  2. C#小爬虫,通过URL进行模拟发送接收数据

    public async Task<string> SendDataAsync(HttpMethod httpMethod, string requestUrl, HttpContent ...

  3. C# 模拟串口发送接收

    一.准备虚拟串口驱动工具 创建俩个虚拟串口,如图: 二.创建两个控制台程序 模拟串口的发送接收数据 1. 接收数据,代码如下: //遍历串行端口名称数组 foreach (string port in ...

  4. 十一、模拟扫码登录微信(用Django简单的布置了下页面)发送接收消息

    为了能够模拟登陆QQ,并获取信息.对扫码登录微信进行了分析.简单的用了一下Django将获取的信息映射到页面上.(python3+pycharm) 主要过程就是: 1.获取二维码 2.扫码登录(有三种 ...

  5. 38KHz,NEC红外模拟发送和接收程序

    /*************************************************************************************************/ ...

  6. nodejs与websocket模拟简单的聊天室

    nodejs与websocket模拟简单的聊天室 server.js const http = require('http') const fs = require('fs') var userip ...

  7. PHP模拟发送POST请求之一、HTTP协议头部解析

    WEB开发中信息基本全是在POST与GET请求与响应中进行,GET因其基于URL的直观,易被我们了解,可POST请求因其信息的隐蔽,在安全的同时,也给开发者们模拟发送带来了麻烦.接下来的几篇博文中,我 ...

  8. 安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制

    安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制 socket 连接采用流的方式进行发送接收数据,采用thread线程的方式. 什么是线程?  详细代码介 ...

  9. outlook 2016 for windows 每次刷新发送接收邮件会弹出登陆界面

    Q: outlook2016 for windows 每次刷新发送接收邮件会弹出登陆界面,office365 ProPlus 都是正常激活了,Word 和Excel都不存在此类问题 A: 排除用户的o ...

随机推荐

  1. jenkins不能执行windows下的命令,cmd可执行。

    1.TortoiseSVN程序在安装时候,选择在windows下的命令行执行,要安装 2.安装后,“C:\Program Files\TortoiseSVN\bin”路径下就存在了命令行的一些指令 3 ...

  2. springboot 创建非web项目及数据源简单使用

    项目组马上要使用springboot来重构程序,首先要对几个比较小的非web项目重构,所以新手入门,简单做了个小例子 代码结构如下: dao层 package com.mysping.myboot00 ...

  3. 5239-回忆京都-洛谷3月赛gg祭

    传送门 题目背景 第十五届东方人气投票 音乐部门 106名 第四次国内不知道东方的人对东方原曲的投票调查 51名 回忆京都副歌我tm吹爆,东方文花帖我tm吹爆! 题目描述 射命丸文在取材中发现了一个好 ...

  4. P1654 OSU!-洛谷luogu

    传送门 题目背景 原 <产品排序> 参见P2577 题目描述 osu 是一款群众喜闻乐见的休闲软件. 我们可以把osu的规则简化与改编成以下的样子: 一共有n次操作,每次操作只有成功与失败 ...

  5. redis学习(四)——Hash数据类型

    一.概述 我们可以将Redis中的Hash类型看成具有String Key和String Value的map容器.所以该类型非常适合于存储值对象的信息.如Username.Password和Age等. ...

  6. 【H5 音乐播放实例】第一节 音乐详情页制作(1)

    本教程是一个H5音乐播放的详情页制作,实现了H5音乐播放,音轨的跳动,已经较为酷炫的UI界面. 通过本教程,您会学到: 1.H5音乐播放 (带音轨) 2.iconfont字体图标库 3.div+css ...

  7. [翻译] ASP.NET Core 2.1.0 发布

    原文: ASP.NET Core 2.1.0 now available 今天,我们很高兴可以发布 ASP.NET Core 2.1.0!这是我们 .NET平台下开源的.跨平台的 Web 框架的最新版 ...

  8. Typescript 发布到npm

    https://blog.csdn.net/yiershan1314/article/details/79999726 https://cloud.tencent.com/developer/arti ...

  9. python第五章:文件--小白博客

    文件操作, 操作文件完毕后一定要记得close # 读,默认是rt(文本的方式读取),rb模式是以字节读取 # 文件路径可以用3中形式表示 f = open(r'C:\Users\fengzi\Des ...

  10. H5 22-通配符选择器

    22-通配符选择器 我是标题 我是段落 我是超链接 --> 我是标题 我是段落 我是超链接 <!DOCTYPE html> <html lang="en"& ...