first upload
This commit is contained in:
62
README.md
62
README.md
@@ -1,2 +1,60 @@
|
||||
# UdpPlugWebsocket
|
||||
这是一个独立的可执行Win32服务端程序,用于桥接终端APP和物联网硬件
|
||||
# UdpPlugWebSocket 简称UPWS服务端程序#
|
||||
|
||||
|
||||
## 项目说明 ##
|
||||
|
||||
公司要做物联网硬件产品,需要一个服务器组件桥接APP软件终端和物联网硬件。 目前比较火的MQTT物联网协议虽然技术先进,但进入门槛较高,用户也相对较为复杂。BG了一番没有找到合适的服务端开源代码,就决定使用自己比较熟悉的.Net技术从头开发一个服务器组件。于是开了这个repository,如果能帮到你,我很高兴。 有问题欢迎与我微信联系: 微信号miuser00,加好友请注明您的来意。
|
||||
|
||||
## 项目简介 ##
|
||||
这是一个独立的可执行Win32服务端程序,用于桥接终端APP和物联网硬件。 APP端为Websocet接口的静态html页面,硬件端为基于Arduino开发的电路,与服务器通讯使用UDP协议通讯(注:为方便您的使用,本Respository亦提供了一个C#编写的简易UDP测试程序用来模拟硬件设备)。 APP通过Webscoket接口发送一个自定义的字符串报文给服务端,服务端根据报文中的ID把报文转发给相同ID的UDP硬件设备(或UDP测试程序)。
|
||||
|
||||

|
||||
|
||||
启动方法:在本地windows环境下运行.\UdpPlugWebsocket\bin\Debug\UdpPlugWebsocket.exe即可按照config.xml中描述的端口启动服务程序。默认UDP端口为7101,Websocket端口为9000。此时外部的UDP连接和Websocket连接都会在UI中显示。其中UDP在终端设备页面中显示,Websocket连接在控制页面中显示,通讯状况在交换面板页面中显示。您可以通过配置->显示调试系信息 打开或关闭UI的通讯Log。
|
||||
|
||||
|
||||
|
||||
|
||||
## 数据包格式 (UDP与Websocket相同)##
|
||||
|
||||

|
||||
|
||||
|
||||
**Endpoint是外部连接的唯一索引。**
|
||||
|
||||
**Endpoint字符串的格式为:"XXX.XXX.XXX.XXX:XXXX" 前四组三位数为IP地址,最后一组四位数为远程端口号**
|
||||
|
||||
##UDP通讯测试##
|
||||
|
||||
运行.\UdpExample\client\bin\Debug\client.exe 在程序控制台中输入如下数据包
|
||||
004832A08000000000200000000000000001234testtest05 即可在终端设备页面看到本机的连接。
|
||||

|
||||
## Websocket通讯测试 ##
|
||||
任意支持websocket的浏览器中运行.\UPW_Browser\index.html?ID=0000000002&MM=0000000000000000与UDP测试程序建立连接(参数区分大小写)
|
||||

|
||||
|
||||
## 目录结构 ##
|
||||
.\UdpPlugWebsocket UPWS服务程序(主服务程序)
|
||||
.\UdpPlugWebsocket\UdpExample UDP测试程序
|
||||
.\UPW_Browser Websocket测试程序
|
||||
.\bin_UPWS 编译后的Win32项目二进制文
|
||||
... 其余目录为参考代码目录,可删除
|
||||
|
||||
|
||||
##编译环境##
|
||||
Visual Studio 2015,C#,Win10
|
||||
|
||||
## 使用到的开源库 ##
|
||||
Websocket-Sharp
|
||||
https://github.com/sta/websocket-sharp
|
||||
Coldairarrow.Util.Sockets
|
||||
https://github.com/Coldairarrow/Sockets
|
||||
|
||||
|
||||
## 关键词 ##
|
||||
|
||||
C#,Websocket,UDP,物联网,异步编程,接口,lamda表达式,线程池,Action,Invoke,Arduino,ESP8266
|
||||
|
||||
## 版权声明 ##
|
||||
|
||||
如果您愿意使用 UdpPlugWebSocket 组件,请遵循 MIT 许可所述内容.
|
||||
37
UPW_Browser/WebSocketClient.html
Normal file
37
UPW_Browser/WebSocketClient.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
var socket;
|
||||
if ("WebSocket" in window) {
|
||||
var ws = new WebSocket("ws://127.0.0.1:9000");
|
||||
socket = ws;
|
||||
ws.onopen = function() {
|
||||
console.log('连接成功');
|
||||
};
|
||||
ws.onmessage = function(evt) {
|
||||
var received_msg = evt.data;
|
||||
document.getElementById("showMes").value+=evt.data+"\n";
|
||||
};
|
||||
ws.onclose = function() {
|
||||
alert("断开了连接");
|
||||
};
|
||||
} else {
|
||||
alert("浏览器不支持WebSocket");
|
||||
}
|
||||
function login(){
|
||||
var message=document.getElementById("name").value+":"+document.getElementById("mes").value;
|
||||
socket.send(message);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<textarea rows="3" cols="30" id="showMes" style="width:300px;height:500px;"></textarea>
|
||||
<br/>
|
||||
<label>名称</label>
|
||||
<input type="text" id="name"/>
|
||||
<br/>
|
||||
<label>消息</label>
|
||||
<input type="text" id="mes"/>
|
||||
<button onclick="login();">发送</button>
|
||||
</body>
|
||||
</html>
|
||||
3
UPW_Browser/main/JustGage.js
Normal file
3
UPW_Browser/main/JustGage.js
Normal file
File diff suppressed because one or more lines are too long
2
UPW_Browser/main/jquery-1.8.3.min.js
vendored
Normal file
2
UPW_Browser/main/jquery-1.8.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
UPW_Browser/main/reconnecting-websocket.min.js
vendored
Normal file
1
UPW_Browser/main/reconnecting-websocket.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(a,b){"function"==typeof define&&define.amd?define([],b):"undefined"!=typeof module&&module.exports?module.exports=b():a.ReconnectingWebSocket=b()}(this,function(){function a(b,c,d){function l(a,b){var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,!1,!1,b),c}var e={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3};d||(d={});for(var f in e)this[f]="undefined"!=typeof d[f]?d[f]:e[f];this.url=b,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var h,g=this,i=!1,j=!1,k=document.createElement("div");k.addEventListener("open",function(a){g.onopen(a)}),k.addEventListener("close",function(a){g.onclose(a)}),k.addEventListener("connecting",function(a){g.onconnecting(a)}),k.addEventListener("message",function(a){g.onmessage(a)}),k.addEventListener("error",function(a){g.onerror(a)}),this.addEventListener=k.addEventListener.bind(k),this.removeEventListener=k.removeEventListener.bind(k),this.dispatchEvent=k.dispatchEvent.bind(k),this.open=function(b){h=new WebSocket(g.url,c||[]),b||k.dispatchEvent(l("connecting")),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",g.url);var d=h,e=setTimeout(function(){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",g.url),j=!0,d.close(),j=!1},g.timeoutInterval);h.onopen=function(){clearTimeout(e),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onopen",g.url),g.protocol=h.protocol,g.readyState=WebSocket.OPEN,g.reconnectAttempts=0;var d=l("open");d.isReconnect=b,b=!1,k.dispatchEvent(d)},h.onclose=function(c){if(clearTimeout(e),h=null,i)g.readyState=WebSocket.CLOSED,k.dispatchEvent(l("close"));else{g.readyState=WebSocket.CONNECTING;var d=l("connecting");d.code=c.code,d.reason=c.reason,d.wasClean=c.wasClean,k.dispatchEvent(d),b||j||((g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onclose",g.url),k.dispatchEvent(l("close")));var e=g.reconnectInterval*Math.pow(g.reconnectDecay,g.reconnectAttempts);setTimeout(function(){g.reconnectAttempts++,g.open(!0)},e>g.maxReconnectInterval?g.maxReconnectInterval:e)}},h.onmessage=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",g.url,b.data);var c=l("message");c.data=b.data,k.dispatchEvent(c)},h.onerror=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onerror",g.url,b),k.dispatchEvent(l("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(b){if(h)return(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","send",g.url,b),h.send(b);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(a,b){"undefined"==typeof a&&(a=1e3),i=!0,h&&h.close(a,b)},this.refresh=function(){h&&h.close()}}return a.prototype.onopen=function(){},a.prototype.onclose=function(){},a.prototype.onconnecting=function(){},a.prototype.onmessage=function(){},a.prototype.onerror=function(){},a.debugAll=!1,a.CONNECTING=WebSocket.CONNECTING,a.OPEN=WebSocket.OPEN,a.CLOSING=WebSocket.CLOSING,a.CLOSED=WebSocket.CLOSED,a});
|
||||
54
UdpExample/UdpExample.sln
Normal file
54
UdpExample/UdpExample.sln
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server", "server\server.csproj", "{BEC0344F-9AE7-4792-8A5D-C60A39D98732}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{6593C9FB-053E-4292-B267-00FFD99C0278}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "udp", "udp\udp.csproj", "{F5BDA737-1EBE-4864-877C-36C5F3295F1E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Debug|x86.Build.0 = Debug|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Release|x86.ActiveCfg = Release|x86
|
||||
{BEC0344F-9AE7-4792-8A5D-C60A39D98732}.Release|x86.Build.0 = Release|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Debug|x86.Build.0 = Debug|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Release|x86.ActiveCfg = Release|x86
|
||||
{6593C9FB-053E-4292-B267-00FFD99C0278}.Release|x86.Build.0 = Release|x86
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{F5BDA737-1EBE-4864-877C-36C5F3295F1E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
51
UdpExample/client/Program.cs
Normal file
51
UdpExample/client/Program.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using udp;
|
||||
namespace client
|
||||
{
|
||||
class Program
|
||||
{
|
||||
private const string _serverIp = "127.0.0.1";
|
||||
private const int _serverPort = 7101;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Client client = new Client();
|
||||
client.ep = new IPEndPoint(IPAddress.Parse(_serverIp), _serverPort);
|
||||
client.Listening();
|
||||
client.Received += new UdpEventHandler(client_Received);
|
||||
while (true)
|
||||
{
|
||||
string tmp = Console.ReadLine();
|
||||
|
||||
byte[] bt = Encoding.Default.GetBytes(tmp);
|
||||
System.Threading.Thread t = new System.Threading.Thread(() =>
|
||||
{
|
||||
client.Send(bt, client.ep);
|
||||
});
|
||||
t.Start();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void client_Received(object sender, UdpEventArgs e)
|
||||
{
|
||||
IPEndPoint ep = e.Remote as IPEndPoint;
|
||||
string tmpReceived = Encoding.Default.GetString(e.Received);
|
||||
Console.WriteLine(ep.Address.ToString() + ":" + ep.Port + "--> " + tmpReceived);
|
||||
}
|
||||
}
|
||||
|
||||
public class Client : Udp
|
||||
{
|
||||
public EndPoint ep;
|
||||
public Client()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
36
UdpExample/client/Properties/AssemblyInfo.cs
Normal file
36
UdpExample/client/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的常规信息通过以下
|
||||
// 特性集控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("client")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("client")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 使此程序集中的类型
|
||||
// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
|
||||
// 则将该类型上的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("9550478a-9201-4126-8828-a465a0fda94d")]
|
||||
|
||||
// 程序集的版本信息由下面四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 内部版本号
|
||||
// 修订号
|
||||
//
|
||||
// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
60
UdpExample/client/client.csproj
Normal file
60
UdpExample/client/client.csproj
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{6593C9FB-053E-4292-B267-00FFD99C0278}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>client</RootNamespace>
|
||||
<AssemblyName>client</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="udp">
|
||||
<HintPath>..\udp\bin\Debug\udp.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
43
UdpExample/server/Program.cs
Normal file
43
UdpExample/server/Program.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using udp;
|
||||
|
||||
namespace server
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static Server server = new Server();
|
||||
static void Main(string[] args)
|
||||
{
|
||||
server.Port = 8000;
|
||||
server.Listening();
|
||||
if (server.IsListening)
|
||||
{
|
||||
server.Received += new UdpEventHandler(server_Received);
|
||||
}
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
static void server_Received(object sender, UdpEventArgs e)
|
||||
{
|
||||
IPEndPoint ep = e.Remote as IPEndPoint;
|
||||
string tmpReceived = Encoding.Default.GetString(e.Received);
|
||||
Console.WriteLine(ep.Address.ToString() + ":" + ep.Port + "--> " + tmpReceived);
|
||||
///自动回复
|
||||
server.Send(Encoding.Default.GetBytes("服务器已收到数据:'" + tmpReceived + "',来自:‘" + ep.Address.ToString() + ":" + ep.Port + "’"), ep);
|
||||
}
|
||||
|
||||
}
|
||||
public class Server : Udp
|
||||
{
|
||||
private EndPoint ep;
|
||||
public Server()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
36
UdpExample/server/Properties/AssemblyInfo.cs
Normal file
36
UdpExample/server/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的常规信息通过以下
|
||||
// 特性集控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("server")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("server")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 使此程序集中的类型
|
||||
// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
|
||||
// 则将该类型上的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("186ec332-5da3-4abe-8970-ad8cafb2c209")]
|
||||
|
||||
// 程序集的版本信息由下面四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 内部版本号
|
||||
// 修订号
|
||||
//
|
||||
// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
60
UdpExample/server/server.csproj
Normal file
60
UdpExample/server/server.csproj
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{BEC0344F-9AE7-4792-8A5D-C60A39D98732}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>server</RootNamespace>
|
||||
<AssemblyName>server</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="udp">
|
||||
<HintPath>..\udp\bin\Debug\udp.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
18
UdpExample/udp/IUdp.cs
Normal file
18
UdpExample/udp/IUdp.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
|
||||
namespace udp
|
||||
{
|
||||
public interface IUdp : IDisposable
|
||||
{
|
||||
event UdpEventHandler Received;
|
||||
|
||||
void Send(byte[] bt, EndPoint ep);
|
||||
|
||||
Socket UdpSocket { get; }
|
||||
}
|
||||
}
|
||||
36
UdpExample/udp/Properties/AssemblyInfo.cs
Normal file
36
UdpExample/udp/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的常规信息通过以下
|
||||
// 特性集控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("udp")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("udp")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 使此程序集中的类型
|
||||
// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
|
||||
// 则将该类型上的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("1202b3ab-a590-4663-bc20-74a8c1dfebc2")]
|
||||
|
||||
// 程序集的版本信息由下面四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 内部版本号
|
||||
// 修订号
|
||||
//
|
||||
// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
146
UdpExample/udp/Udp.cs
Normal file
146
UdpExample/udp/Udp.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace udp
|
||||
{
|
||||
public delegate void UdpEventHandler(object sender, UdpEventArgs e);
|
||||
|
||||
public abstract class Udp : IUdp
|
||||
{
|
||||
public event UdpEventHandler Received;
|
||||
|
||||
private int _port;
|
||||
private string _ip;
|
||||
public bool IsListening { get; private set; }
|
||||
private Socket _sck;
|
||||
|
||||
public Socket UdpSocket
|
||||
{
|
||||
get { return _sck; }
|
||||
}
|
||||
public string Ip
|
||||
{
|
||||
get { return _ip; }
|
||||
set { _ip = value; }
|
||||
}
|
||||
public int Port
|
||||
{
|
||||
get { return _port; }
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
if (value > 65536)
|
||||
value = 65536;
|
||||
_port = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Udp()
|
||||
{
|
||||
_sck = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
_sck.ReceiveBufferSize = UInt16.MaxValue * 8;
|
||||
//log
|
||||
System.Diagnostics.Trace.Listeners.Clear();
|
||||
System.Diagnostics.Trace.AutoFlush = true;
|
||||
System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener("log.txt"));
|
||||
}
|
||||
|
||||
|
||||
public void Listening()
|
||||
{
|
||||
|
||||
IPAddress ip = IPAddress.Any;
|
||||
try
|
||||
{
|
||||
if (this._ip != null)
|
||||
if (!IPAddress.TryParse(this._ip, out ip))
|
||||
throw new ArgumentException("IP地址错误", "Ip");
|
||||
_sck.Bind(new IPEndPoint(ip, this._port));
|
||||
|
||||
UdpState state = new UdpState();
|
||||
state.Socket = _sck;
|
||||
state.Remote = new IPEndPoint(IPAddress.Any, 0);
|
||||
_sck.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.Remote, new AsyncCallback(EndReceiveFrom), state);
|
||||
|
||||
IsListening = true;
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
IsListening = false;
|
||||
System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString() + "\t" + ex.Message);
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsListening = false;
|
||||
System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString() + "\t" + ex.Message);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
private void EndReceiveFrom(IAsyncResult ir)
|
||||
{
|
||||
if (IsListening)
|
||||
{
|
||||
UdpState state = ir.AsyncState as UdpState;
|
||||
try
|
||||
{
|
||||
if (ir.IsCompleted)
|
||||
{
|
||||
int length = state.Socket.EndReceiveFrom(ir, ref state.Remote);
|
||||
byte[] btReceived = new byte[length];
|
||||
Buffer.BlockCopy(state.Buffer, 0, btReceived, 0, length);
|
||||
OnReceived(new UdpEventArgs(btReceived, state.Remote));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString() + "\t" + ex.Message+ex.Source);
|
||||
}
|
||||
finally
|
||||
{
|
||||
state.Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.Remote, new AsyncCallback(EndReceiveFrom), state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReceived(UdpEventArgs e)
|
||||
{
|
||||
if (this.Received != null)
|
||||
{
|
||||
Received(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(byte[] bt, EndPoint ep)
|
||||
{
|
||||
if (_sck == null) return;
|
||||
try
|
||||
{
|
||||
this._sck.SendTo(bt, ep);
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString() + "\t" + ex.Message);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_sck == null) return;
|
||||
|
||||
using (_sck) ;
|
||||
//this.IsListening = false;
|
||||
//this._sck.Blocking = false;
|
||||
//this._sck.Shutdown(SocketShutdown.Both);
|
||||
//this._sck.Close();
|
||||
//this._sck = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
30
UdpExample/udp/UdpEventArgs.cs
Normal file
30
UdpExample/udp/UdpEventArgs.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
namespace udp
|
||||
{
|
||||
public class UdpEventArgs : EventArgs
|
||||
{
|
||||
private EndPoint _remote;
|
||||
|
||||
private byte[] _rec;
|
||||
|
||||
public byte[] Received
|
||||
{
|
||||
get { return _rec; }
|
||||
}
|
||||
public EndPoint Remote
|
||||
{
|
||||
get { return _remote; }
|
||||
}
|
||||
|
||||
public UdpEventArgs(byte[] data, EndPoint remote)
|
||||
{
|
||||
this._remote = remote;
|
||||
this._rec = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
UdpExample/udp/UdpState.cs
Normal file
21
UdpExample/udp/UdpState.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace udp
|
||||
{
|
||||
internal class UdpState
|
||||
{
|
||||
public byte[] Buffer;
|
||||
public EndPoint Remote;
|
||||
public Socket Socket;
|
||||
|
||||
public UdpState()
|
||||
{
|
||||
Buffer = new byte[65536];
|
||||
}
|
||||
}
|
||||
}
|
||||
58
UdpExample/udp/udp.csproj
Normal file
58
UdpExample/udp/udp.csproj
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{F5BDA737-1EBE-4864-877C-36C5F3295F1E}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>udp</RootNamespace>
|
||||
<AssemblyName>udp</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="IUdp.cs" />
|
||||
<Compile Include="Udp.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UdpEventArgs.cs" />
|
||||
<Compile Include="UdpState.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
22
UdpPlugWebsocket.sln
Normal file
22
UdpPlugWebsocket.sln
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UdpPlugWebsocket", "UdpPlugWebsocket\UdpPlugWebsocket.csproj", "{54CF701B-B076-4FC3-8A01-7434111A1C5B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{54CF701B-B076-4FC3-8A01-7434111A1C5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{54CF701B-B076-4FC3-8A01-7434111A1C5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{54CF701B-B076-4FC3-8A01-7434111A1C5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{54CF701B-B076-4FC3-8A01-7434111A1C5B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
6
UdpPlugWebsocket/App.config
Normal file
6
UdpPlugWebsocket/App.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
191
UdpPlugWebsocket/Browser.Designer.cs
generated
Normal file
191
UdpPlugWebsocket/Browser.Designer.cs
generated
Normal file
@@ -0,0 +1,191 @@
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
partial class Browser
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.dgv_browsers = new System.Windows.Forms.DataGridView();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.txt_Send = new System.Windows.Forms.TextBox();
|
||||
this.btn_Send = new System.Windows.Forms.Button();
|
||||
this.splitter1 = new System.Windows.Forms.Splitter();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.dataGridView1 = new System.Windows.Forms.DataGridView();
|
||||
this.groupBox1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv_browsers)).BeginInit();
|
||||
this.panel1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.dgv_browsers);
|
||||
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.groupBox1.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.groupBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(830, 600);
|
||||
this.groupBox1.TabIndex = 2;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "浏览客户端:";
|
||||
//
|
||||
// dgv_browsers
|
||||
//
|
||||
this.dgv_browsers.AllowUserToAddRows = false;
|
||||
this.dgv_browsers.BackgroundColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.dgv_browsers.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dgv_browsers.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dgv_browsers.GridColor = System.Drawing.Color.Snow;
|
||||
this.dgv_browsers.Location = new System.Drawing.Point(3, 25);
|
||||
this.dgv_browsers.MultiSelect = false;
|
||||
this.dgv_browsers.Name = "dgv_browsers";
|
||||
this.dgv_browsers.ReadOnly = true;
|
||||
this.dgv_browsers.RowHeadersVisible = false;
|
||||
this.dgv_browsers.RowHeadersWidth = 4;
|
||||
this.dgv_browsers.RowTemplate.Height = 23;
|
||||
this.dgv_browsers.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dgv_browsers.Size = new System.Drawing.Size(824, 572);
|
||||
this.dgv_browsers.TabIndex = 0;
|
||||
this.dgv_browsers.SelectionChanged += new System.EventHandler(this.dgv_browsers_SelectionChanged);
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.Controls.Add(this.txt_Send);
|
||||
this.panel1.Controls.Add(this.btn_Send);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.panel1.Location = new System.Drawing.Point(0, 600);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(830, 25);
|
||||
this.panel1.TabIndex = 5;
|
||||
//
|
||||
// txt_Send
|
||||
//
|
||||
this.txt_Send.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txt_Send.Font = new System.Drawing.Font("宋体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.txt_Send.Location = new System.Drawing.Point(0, 0);
|
||||
this.txt_Send.Name = "txt_Send";
|
||||
this.txt_Send.Size = new System.Drawing.Size(744, 26);
|
||||
this.txt_Send.TabIndex = 0;
|
||||
//
|
||||
// btn_Send
|
||||
//
|
||||
this.btn_Send.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.btn_Send.Location = new System.Drawing.Point(744, 0);
|
||||
this.btn_Send.Name = "btn_Send";
|
||||
this.btn_Send.Size = new System.Drawing.Size(86, 25);
|
||||
this.btn_Send.TabIndex = 1;
|
||||
this.btn_Send.Text = "发送";
|
||||
this.btn_Send.UseVisualStyleBackColor = true;
|
||||
this.btn_Send.Click += new System.EventHandler(this.btn_Send_Click);
|
||||
//
|
||||
// splitter1
|
||||
//
|
||||
this.splitter1.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.splitter1.Location = new System.Drawing.Point(0, 368);
|
||||
this.splitter1.Name = "splitter1";
|
||||
this.splitter1.Size = new System.Drawing.Size(830, 10);
|
||||
this.splitter1.TabIndex = 9;
|
||||
this.splitter1.TabStop = false;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.richTextBox1);
|
||||
this.groupBox2.Controls.Add(this.dataGridView1);
|
||||
this.groupBox2.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.groupBox2.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.groupBox2.Location = new System.Drawing.Point(0, 378);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(830, 222);
|
||||
this.groupBox2.TabIndex = 8;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "接收:";
|
||||
//
|
||||
// richTextBox1
|
||||
//
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.richTextBox1.Location = new System.Drawing.Point(3, 25);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.Size = new System.Drawing.Size(824, 194);
|
||||
this.richTextBox1.TabIndex = 5;
|
||||
this.richTextBox1.Text = "";
|
||||
//
|
||||
// dataGridView1
|
||||
//
|
||||
this.dataGridView1.AllowUserToAddRows = false;
|
||||
this.dataGridView1.BackgroundColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dataGridView1.GridColor = System.Drawing.Color.Snow;
|
||||
this.dataGridView1.Location = new System.Drawing.Point(3, 25);
|
||||
this.dataGridView1.MultiSelect = false;
|
||||
this.dataGridView1.Name = "dataGridView1";
|
||||
this.dataGridView1.ReadOnly = true;
|
||||
this.dataGridView1.RowHeadersVisible = false;
|
||||
this.dataGridView1.RowHeadersWidth = 4;
|
||||
this.dataGridView1.RowTemplate.Height = 23;
|
||||
this.dataGridView1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dataGridView1.Size = new System.Drawing.Size(824, 194);
|
||||
this.dataGridView1.TabIndex = 0;
|
||||
//
|
||||
// Browser
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(830, 625);
|
||||
this.Controls.Add(this.splitter1);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.panel1);
|
||||
this.Name = "Browser";
|
||||
this.Text = "Browser";
|
||||
this.Load += new System.EventHandler(this.Browser_Load);
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv_browsers)).EndInit();
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.DataGridView dgv_browsers;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.TextBox txt_Send;
|
||||
private System.Windows.Forms.Button btn_Send;
|
||||
private System.Windows.Forms.Splitter splitter1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||
private System.Windows.Forms.DataGridView dataGridView1;
|
||||
}
|
||||
}
|
||||
222
UdpPlugWebsocket/Browser.cs
Normal file
222
UdpPlugWebsocket/Browser.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using WebSocketSharp.Server;
|
||||
using WebSocketSharp;
|
||||
using System.IO;
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
public partial class Browser : Form
|
||||
{
|
||||
string s_output;
|
||||
//本Websocket服务对象
|
||||
public WebSocketServer server;
|
||||
//人工选中的连接对象
|
||||
public static IWebSocketSession curr;
|
||||
private static Browser _instance;
|
||||
|
||||
public Browser()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
server = new WebSocketServer("ws://0.0.0.0:"+SetupForm.cfg.BrowserPort);
|
||||
server.AddWebSocketService<Laputa>("/");
|
||||
server.Start();
|
||||
}
|
||||
private void Browser_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送字节
|
||||
/// </summary>
|
||||
public void Send(string EndpointString,byte[] bytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
IWebSocketSession session=server.WebSocketServices["/"].Sessions.Sessions.Where(x => { return x.Context.UserEndPoint.ToString() == EndpointString; }).FirstOrDefault();
|
||||
server.WebSocketServices["/"].Sessions.SendToAsync(System.Text.Encoding.Default.GetString(bytes), session.ID, null);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
HandleError?.Invoke(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
public void RefreshDataGrid(WebSocketSessionManager wsm)
|
||||
{
|
||||
DataTable dt = GetConnectionTable(wsm);
|
||||
{
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
lock (dt.Rows.SyncRoot)
|
||||
{
|
||||
dgv_browsers.DataSource = dt.Copy();
|
||||
}
|
||||
dgv_browsers.Columns[0].Width = 400;
|
||||
dgv_browsers.Columns[1].Width = 200;
|
||||
}));
|
||||
}
|
||||
}
|
||||
private DataTable GetConnectionTable(WebSocketSessionManager wsm)
|
||||
{
|
||||
|
||||
DataTable dt = new DataTable();
|
||||
dt.Columns.Add("ID");
|
||||
dt.Columns.Add("EndPoint");
|
||||
dt.Columns.Add("State");
|
||||
|
||||
lock (wsm.Sessions)
|
||||
{
|
||||
foreach (IWebSocketSession session in wsm.Sessions.ToArray())
|
||||
{
|
||||
|
||||
DataRow dr = dt.NewRow();
|
||||
dr[0] = session.ID;
|
||||
dr[1] = session.Context.UserEndPoint;
|
||||
dr[2] = session.State;
|
||||
dt.Rows.Add(dr);
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
|
||||
}
|
||||
public static Browser Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new Browser();
|
||||
return _instance;
|
||||
}
|
||||
private set { _instance = value; }
|
||||
}
|
||||
public void LogMessage(string message)
|
||||
{
|
||||
HandleMessage?.Invoke(message);
|
||||
}
|
||||
public void LogError(string message)
|
||||
{
|
||||
HandleError?.Invoke(message);
|
||||
}
|
||||
#region 消息和错误事件
|
||||
/// <summary>
|
||||
/// 消息处理程序
|
||||
/// </summary>
|
||||
public Action<string> HandleMessage { get; set; }
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<string> HandleError { get; set; }
|
||||
|
||||
|
||||
#endregion
|
||||
private void btn_Send_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
server.WebSocketServices["/"].Sessions.SendToAsync(txt_Send.Text, curr.ID, null);
|
||||
}catch (Exception ex)
|
||||
{
|
||||
HandleError?.Invoke(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
private void dgv_browsers_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (dgv_browsers.SelectedRows.Count > 0)
|
||||
{
|
||||
string tag = dgv_browsers.SelectedRows[0].Cells["EndPoint"].Value.ToString();
|
||||
curr = server.WebSocketServices["/"].Sessions.Sessions.Where(x =>
|
||||
{
|
||||
var Id = (string)x.Context.UserEndPoint.ToString();
|
||||
return Id == tag;
|
||||
}).FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
curr = null;
|
||||
}
|
||||
}
|
||||
public void SetOutput(string text)
|
||||
{
|
||||
//决定是否屏显
|
||||
if (SetupForm.cfg.EnableScreenLog == false) return;
|
||||
|
||||
text = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + " |" + text;
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
s_output = s_output + text.Replace("\0", "") + "\r";
|
||||
|
||||
if ((s_output.Length) > 5000)
|
||||
{
|
||||
s_output = s_output.Substring(s_output.Length - 5000, 5000);
|
||||
}
|
||||
//滚到最后
|
||||
this.richTextBox1.Text = s_output;
|
||||
this.richTextBox1.Select(richTextBox1.TextLength, 0);
|
||||
//this.richTextBox1.Focus();
|
||||
this.richTextBox1.ScrollToCaret();
|
||||
|
||||
}));
|
||||
}
|
||||
#region 客户端连接事件
|
||||
/// <summary>
|
||||
/// 当新客户端连接后执行
|
||||
/// </summary>
|
||||
public Action<WebSocketSharp.Net.WebSockets.WebSocketContext> HandleNewWebSocketClientConnected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接接受新的消息后调用
|
||||
/// </summary>
|
||||
public Action<byte[], WebSocketSharp.Net.WebSockets.WebSocketContext> HandleWebSocketRecMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接发送消息后回调
|
||||
/// </summary>
|
||||
public Action<byte[], WebSocketSharp.Net.WebSockets.WebSocketContext> HandleWebSocketSendMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接关闭后回调
|
||||
/// </summary>
|
||||
public Action<WebSocketSharp.Net.WebSockets.WebSocketContext> HandleWebSocketClientClose { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
public class Laputa : WebSocketBehavior
|
||||
{
|
||||
|
||||
protected override void OnOpen()
|
||||
{
|
||||
|
||||
Browser.Instance. LogMessage( Context.UserEndPoint.ToString() + " was accepted" + " Websocket ID is " + ID);
|
||||
Browser.Instance.RefreshDataGrid(Sessions);
|
||||
Browser.Instance.HandleNewWebSocketClientConnected?.Invoke(Context);
|
||||
base.OnOpen();
|
||||
}
|
||||
protected override void OnClose(CloseEventArgs e)
|
||||
{
|
||||
Browser.Instance.LogMessage("Websocket "+this.ID + " was closed");
|
||||
Browser.Instance.RefreshDataGrid(Sessions);
|
||||
Browser.Instance.HandleWebSocketClientClose?.Invoke(Context);
|
||||
base.OnClose(e);
|
||||
|
||||
}
|
||||
protected override void OnMessage(MessageEventArgs e)
|
||||
{
|
||||
string s_data = e.Data;
|
||||
Logger log = new Logger();
|
||||
//Browser.Instance.LogMessage(Context.UserEndPoint.ToString() + " is Saying: " + e.Data);
|
||||
Browser.Instance.HandleWebSocketRecMsg?.Invoke(System.Text.Encoding.Default.GetBytes(e.Data), Context);
|
||||
//Console.Write(e.Data);
|
||||
Browser.Instance.SetOutput(Context.UserEndPoint.ToString()+" received " +e.Data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
120
UdpPlugWebsocket/Browser.resx
Normal file
120
UdpPlugWebsocket/Browser.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
2
UdpPlugWebsocket/ClassDiagram1.cd
Normal file
2
UdpPlugWebsocket/ClassDiagram1.cd
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ClassDiagram />
|
||||
48
UdpPlugWebsocket/ClassDiagram2.cd
Normal file
48
UdpPlugWebsocket/ClassDiagram2.cd
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ClassDiagram MajorVersion="1" MinorVersion="1">
|
||||
<Class Name="Miuser.NUDP.Sockets.SocketServer">
|
||||
<Position X="0.5" Y="0.5" Width="2.75" />
|
||||
<Members>
|
||||
<Property Name="_clientList" Hidden="true" />
|
||||
<Property Name="_ip" Hidden="true" />
|
||||
<Property Name="_isListen" Hidden="true" />
|
||||
<Property Name="_port" Hidden="true" />
|
||||
<Method Name="EndReceiveFrom" Hidden="true" />
|
||||
<Method Name="HandleConnClientClose" Hidden="true" />
|
||||
<Field Name="Instance" Hidden="true" />
|
||||
<Property Name="IsListening" Hidden="true" />
|
||||
<Method Name="RemoveConnection" Hidden="true" />
|
||||
<Method Name="RemoveInactiveConnection" Hidden="true" />
|
||||
<Method Name="RemoveInactiveConnections" Hidden="true" />
|
||||
<Property Name="RWLock_ClientList" Hidden="true" />
|
||||
<Method Name="SocketServer" Hidden="true" />
|
||||
</Members>
|
||||
<NestedTypes>
|
||||
<Class Name="Miuser.NUDP.Sockets.SocketServer.UdpState" Collapsed="true">
|
||||
<TypeIdentifier>
|
||||
<NewMemberFileName>Device\SocketServer.cs</NewMemberFileName>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
</NestedTypes>
|
||||
<TypeIdentifier>
|
||||
<HashCode>gBQAIQAAAAIEUAggQEBgABAAAkAAAQAAQAiAQAABAAg=</HashCode>
|
||||
<FileName>Device\SocketServer.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Miuser.NUDP.Sockets.SocketConnection">
|
||||
<Position X="3.5" Y="0.5" Width="2.5" />
|
||||
<Members>
|
||||
<Field Name="_server" Hidden="true" />
|
||||
<Method Name="InitTimer" Hidden="true" />
|
||||
<Field Name="LIFELIMIT" Hidden="true" />
|
||||
<Method Name="SocketConnection" Hidden="true" />
|
||||
<Field Name="timer" Hidden="true" />
|
||||
<Method Name="TimerUp" Hidden="true" />
|
||||
</Members>
|
||||
<TypeIdentifier>
|
||||
<HashCode>wAQEAAAAAAAgQAAAUAAAAAAAAAAAAgAAAAoAAAAACAQ=</HashCode>
|
||||
<FileName>Device\SocketConnection.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Font Name="Microsoft YaHei UI" Size="9" />
|
||||
</ClassDiagram>
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{5DF7AFDF-6B88-42AD-B855-4EB9BF0E2495}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Coldairarrow.Util.Sockets</RootNamespace>
|
||||
<AssemblyName>Coldairarrow.Util.Sockets</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\Coldairarrow.Util.Sockets.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SocketClient.cs" />
|
||||
<Compile Include="SocketConnection.cs" />
|
||||
<Compile Include="SocketServer.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("01.Coldairarrow.Util.Sockets")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("01.Coldairarrow.Util.Sockets")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("5df7afdf-6b88-42ad-b855-4eb9bf0e2495")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,241 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace Coldairarrow.Util.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket客户端
|
||||
/// </summary>
|
||||
public class SocketClient
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数,连接服务器IP地址默认为本机127.0.0.1
|
||||
/// </summary>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public SocketClient(int port)
|
||||
{
|
||||
_ip = "127.0.0.1";
|
||||
_port = port;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">监听的IP地址</param>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public SocketClient(string ip, int port)
|
||||
{
|
||||
_ip = ip;
|
||||
_port = port;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 内部成员
|
||||
|
||||
private Socket _socket = null;
|
||||
private string _ip = "";
|
||||
private int _port = 0;
|
||||
private bool _isRec=true;
|
||||
private bool IsSocketConnected()
|
||||
{
|
||||
bool part1 = _socket.Poll(1000, SelectMode.SelectRead);
|
||||
bool part2 = (_socket.Available == 0);
|
||||
if (part1 && part2)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始接受客户端消息
|
||||
/// </summary>
|
||||
public void StartRecMsg()
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] container = new byte[1024 * 1024 * 2];
|
||||
_socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int length = _socket.EndReceive(asyncResult);
|
||||
|
||||
//马上进行下一轮接受,增加吞吐量
|
||||
if (length > 0 && _isRec && IsSocketConnected())
|
||||
StartRecMsg();
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
byte[] recBytes = new byte[length];
|
||||
Array.Copy(container, 0, recBytes, 0, length);
|
||||
|
||||
//处理消息
|
||||
HandleRecMsg?.BeginInvoke(recBytes, this,null,null);
|
||||
}
|
||||
else
|
||||
Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
Close();
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 外部接口
|
||||
|
||||
/// <summary>
|
||||
/// 开始服务,连接服务端
|
||||
/// </summary>
|
||||
public void StartClient()
|
||||
{
|
||||
try
|
||||
{
|
||||
//实例化 套接字 (ip4寻址协议,流式传输,TCP协议)
|
||||
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
//创建 ip对象
|
||||
IPAddress address = IPAddress.Parse(_ip);
|
||||
//创建网络节点对象 包含 ip和port
|
||||
IPEndPoint endpoint = new IPEndPoint(address, _port);
|
||||
//将 监听套接字 绑定到 对应的IP和端口
|
||||
_socket.BeginConnect(endpoint, asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket.EndConnect(asyncResult);
|
||||
//开始接受服务器消息
|
||||
StartRecMsg();
|
||||
|
||||
HandleClientStarted?.BeginInvoke(this,null,null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据
|
||||
/// </summary>
|
||||
/// <param name="bytes">数据字节</param>
|
||||
public void Send(byte[] bytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int length = _socket.EndSend(asyncResult);
|
||||
HandleSendMsg?.BeginInvoke(bytes, this,null,null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字符串(默认使用UTF-8编码)
|
||||
/// </summary>
|
||||
/// <param name="msgStr">字符串</param>
|
||||
public void Send(string msgStr)
|
||||
{
|
||||
Send(Encoding.UTF8.GetBytes(msgStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字符串(使用自定义编码)
|
||||
/// </summary>
|
||||
/// <param name="msgStr">字符串消息</param>
|
||||
/// <param name="encoding">使用的编码</param>
|
||||
public void Send(string msgStr, Encoding encoding)
|
||||
{
|
||||
Send(encoding.GetBytes(msgStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 传入自定义属性
|
||||
/// </summary>
|
||||
public object Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关闭与服务器的连接
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isRec = false;
|
||||
_socket.Disconnect(false);
|
||||
HandleClientClose?.BeginInvoke(this,null,null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socket.Dispose();
|
||||
GC.Collect();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 事件处理
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接建立后回调
|
||||
/// </summary>
|
||||
public Action<SocketClient> HandleClientStarted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理接受消息的委托
|
||||
/// </summary>
|
||||
public Action<byte[], SocketClient> HandleRecMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接发送消息后回调
|
||||
/// </summary>
|
||||
public Action<byte[], SocketClient> HandleSendMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接关闭后回调
|
||||
/// </summary>
|
||||
public Action<SocketClient> HandleClientClose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace Coldairarrow.Util.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket连接,双向通信
|
||||
/// </summary>
|
||||
public class SocketConnection
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="socket">维护的Socket对象</param>
|
||||
/// <param name="server">维护此连接的服务对象</param>
|
||||
public SocketConnection(Socket socket,SocketServer server)
|
||||
{
|
||||
_socket = socket;
|
||||
_server = server;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 私有成员
|
||||
|
||||
private readonly Socket _socket;
|
||||
private bool _isRec=true;
|
||||
private SocketServer _server = null;
|
||||
private bool IsSocketConnected()
|
||||
{
|
||||
bool part1 = _socket.Poll(1000, SelectMode.SelectRead);
|
||||
bool part2 = (_socket.Available == 0);
|
||||
if (part1 && part2)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 外部接口
|
||||
|
||||
/// <summary>
|
||||
/// 开始接受客户端消息
|
||||
/// </summary>
|
||||
public void StartRecMsg()
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] container = new byte[1024 * 1024 * 4];
|
||||
_socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int length = _socket.EndReceive(asyncResult);
|
||||
|
||||
//马上进行下一轮接受,增加吞吐量
|
||||
if (length > 0 && _isRec && IsSocketConnected())
|
||||
StartRecMsg();
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
byte[] recBytes = new byte[length];
|
||||
Array.Copy(container, 0, recBytes, 0, length);
|
||||
try
|
||||
{
|
||||
//处理消息
|
||||
HandleRecMsg?.BeginInvoke(recBytes, this, _server, null, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.Invoke(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
Close();
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据
|
||||
/// </summary>
|
||||
/// <param name="bytes">数据字节</param>
|
||||
public void Send(byte[] bytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int length = _socket.EndSend(asyncResult);
|
||||
HandleSendMsg?.BeginInvoke(bytes, this, _server,null,null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字符串(默认使用UTF-8编码)
|
||||
/// </summary>
|
||||
/// <param name="msgStr">字符串</param>
|
||||
public void Send(string msgStr)
|
||||
{
|
||||
Send(Encoding.UTF8.GetBytes(msgStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字符串(使用自定义编码)
|
||||
/// </summary>
|
||||
/// <param name="msgStr">字符串消息</param>
|
||||
/// <param name="encoding">使用的编码</param>
|
||||
public void Send(string msgStr,Encoding encoding)
|
||||
{
|
||||
Send(encoding.GetBytes(msgStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 传入自定义属性
|
||||
/// </summary>
|
||||
public object Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关闭当前连接
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isRec = false;
|
||||
_socket.Disconnect(false);
|
||||
_server.RemoveConnection(this);
|
||||
HandleClientClose?.BeginInvoke(this, _server,null,null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socket.Dispose();
|
||||
GC.Collect();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 事件处理
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接接受新的消息后调用
|
||||
/// </summary>
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接发送消息后回调
|
||||
/// </summary>
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接关闭后回调
|
||||
/// </summary>
|
||||
public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace Coldairarrow.Util.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket服务端
|
||||
/// </summary>
|
||||
public class SocketServer
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">监听的IP地址</param>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public SocketServer(string ip, int port)
|
||||
{
|
||||
_ip = ip;
|
||||
_port = port;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数,监听IP地址默认为本机0.0.0.0
|
||||
/// </summary>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public SocketServer(int port)
|
||||
{
|
||||
_ip = "0.0.0.0";
|
||||
_port = port;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 内部成员
|
||||
|
||||
private Socket _socket { get; set; } = null;
|
||||
private string _ip { get; set; } = "";
|
||||
private int _port { get; set; } = 0;
|
||||
private bool _isListen { get; set; } = true;
|
||||
private void StartListen()
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket.BeginAccept(asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Socket newSocket = _socket.EndAccept(asyncResult);
|
||||
|
||||
//马上进行下一轮监听,增加吞吐量
|
||||
if (_isListen)
|
||||
StartListen();
|
||||
|
||||
SocketConnection newConnection = new SocketConnection(newSocket, this)
|
||||
{
|
||||
HandleRecMsg = HandleRecMsg == null ? null : new Action<byte[], SocketConnection, SocketServer>(HandleRecMsg),
|
||||
HandleClientClose = HandleClientClose == null ? null : new Action<SocketConnection, SocketServer>(HandleClientClose),
|
||||
HandleSendMsg = HandleSendMsg == null ? null : new Action<byte[], SocketConnection, SocketServer>(HandleSendMsg),
|
||||
HandleException = HandleException == null ? null : new Action<Exception>(HandleException)
|
||||
};
|
||||
|
||||
newConnection.StartRecMsg();
|
||||
AddConnection(newConnection);
|
||||
HandleNewClientConnected?.BeginInvoke(this, newConnection, null, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex, null, null);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex, null, null);
|
||||
}
|
||||
}
|
||||
private LinkedList<SocketConnection> _clientList { get; } = new LinkedList<SocketConnection>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region 外部接口
|
||||
|
||||
/// <summary>
|
||||
/// 开始服务,监听客户端
|
||||
/// </summary>
|
||||
public void StartServer()
|
||||
{
|
||||
try
|
||||
{
|
||||
//实例化套接字(ip4寻址协议,流式传输,TCP协议)
|
||||
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
//创建ip对象
|
||||
IPAddress address = IPAddress.Parse(_ip);
|
||||
//创建网络节点对象包含ip和port
|
||||
IPEndPoint endpoint = new IPEndPoint(address, _port);
|
||||
//将 监听套接字绑定到 对应的IP和端口
|
||||
_socket.Bind(endpoint);
|
||||
//设置监听队列长度为Int32最大值(同时能够处理连接请求数量)
|
||||
_socket.Listen(int.MaxValue);
|
||||
//开始监听客户端
|
||||
StartListen();
|
||||
HandleServerStarted?.BeginInvoke(this, null, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 维护客户端列表的读写锁
|
||||
/// </summary>
|
||||
public ReaderWriterLockSlim RWLock_ClientList { get; } = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// 关闭指定客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
public void CloseConnection(SocketConnection theConnection)
|
||||
{
|
||||
theConnection.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">需要添加的客户端连接</param>
|
||||
public void AddConnection(SocketConnection theConnection)
|
||||
{
|
||||
RWLock_ClientList.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_clientList.AddLast(theConnection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定的客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
public void RemoveConnection(SocketConnection theConnection)
|
||||
{
|
||||
RWLock_ClientList.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_clientList.Remove(theConnection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过条件获取客户端连接列表
|
||||
/// </summary>
|
||||
/// <param name="predicate">筛选条件</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SocketConnection> GetConnectionList(Func<SocketConnection, bool> predicate)
|
||||
{
|
||||
RWLock_ClientList.EnterReadLock();
|
||||
try
|
||||
{
|
||||
return _clientList.Where(predicate);
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有客户端连接列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SocketConnection> GetConnectionList()
|
||||
{
|
||||
return _clientList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 寻找特定条件的客户端连接
|
||||
/// </summary>
|
||||
/// <param name="predicate">筛选条件</param>
|
||||
/// <returns></returns>
|
||||
public SocketConnection GetTheConnection(Func<SocketConnection, bool> predicate)
|
||||
{
|
||||
RWLock_ClientList.EnterReadLock();
|
||||
try
|
||||
{
|
||||
return _clientList.Where(predicate).FirstOrDefault();
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取客户端连接数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetConnectionCount()
|
||||
{
|
||||
RWLock_ClientList.EnterReadLock();
|
||||
try
|
||||
{
|
||||
return _clientList.Count;
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 公共事件
|
||||
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 服务端事件
|
||||
|
||||
/// <summary>
|
||||
/// 服务启动后执行
|
||||
/// </summary>
|
||||
public Action<SocketServer> HandleServerStarted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当新客户端连接后执行
|
||||
/// </summary>
|
||||
public Action<SocketServer, SocketConnection> HandleNewClientConnected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务端关闭客户端后执行
|
||||
/// </summary>
|
||||
public Action<SocketServer, SocketConnection> HandleCloseClient { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 客户端连接事件
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接接受新的消息后调用
|
||||
/// </summary>
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接发送消息后回调
|
||||
/// </summary>
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接关闭后回调
|
||||
/// </summary>
|
||||
public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
https://github.com/Coldairarrow/Sockets
|
||||
|
||||
ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ΪTCP/IPЭ<50>飬<EFBFBD><E9A3AC><EFBFBD><EFBFBD>ΪUDPЭ<50><D0AD>
|
||||
192
UdpPlugWebsocket/Device/Device.Designer.cs
generated
Normal file
192
UdpPlugWebsocket/Device/Device.Designer.cs
generated
Normal file
@@ -0,0 +1,192 @@
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
partial class Device
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.dgv_devices = new System.Windows.Forms.DataGridView();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.txt_Send = new System.Windows.Forms.TextBox();
|
||||
this.btn_Send = new System.Windows.Forms.Button();
|
||||
this.splitter1 = new System.Windows.Forms.Splitter();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.dataGridView1 = new System.Windows.Forms.DataGridView();
|
||||
this.groupBox1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv_devices)).BeginInit();
|
||||
this.panel1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.dgv_devices);
|
||||
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.groupBox1.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.groupBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(872, 614);
|
||||
this.groupBox1.TabIndex = 3;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "终端设备:";
|
||||
this.groupBox1.Enter += new System.EventHandler(this.groupBox1_Enter);
|
||||
//
|
||||
// dgv_devices
|
||||
//
|
||||
this.dgv_devices.AllowUserToAddRows = false;
|
||||
this.dgv_devices.BackgroundColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.dgv_devices.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dgv_devices.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dgv_devices.GridColor = System.Drawing.Color.Snow;
|
||||
this.dgv_devices.Location = new System.Drawing.Point(3, 25);
|
||||
this.dgv_devices.MultiSelect = false;
|
||||
this.dgv_devices.Name = "dgv_devices";
|
||||
this.dgv_devices.ReadOnly = true;
|
||||
this.dgv_devices.RowHeadersVisible = false;
|
||||
this.dgv_devices.RowHeadersWidth = 4;
|
||||
this.dgv_devices.RowTemplate.Height = 23;
|
||||
this.dgv_devices.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dgv_devices.Size = new System.Drawing.Size(866, 586);
|
||||
this.dgv_devices.TabIndex = 0;
|
||||
this.dgv_devices.SelectionChanged += new System.EventHandler(this.dgv_devices_SelectionChanged);
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.Controls.Add(this.txt_Send);
|
||||
this.panel1.Controls.Add(this.btn_Send);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.panel1.Location = new System.Drawing.Point(0, 614);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(872, 25);
|
||||
this.panel1.TabIndex = 4;
|
||||
//
|
||||
// txt_Send
|
||||
//
|
||||
this.txt_Send.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txt_Send.Font = new System.Drawing.Font("宋体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.txt_Send.Location = new System.Drawing.Point(0, 0);
|
||||
this.txt_Send.Name = "txt_Send";
|
||||
this.txt_Send.Size = new System.Drawing.Size(786, 26);
|
||||
this.txt_Send.TabIndex = 0;
|
||||
//
|
||||
// btn_Send
|
||||
//
|
||||
this.btn_Send.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.btn_Send.Location = new System.Drawing.Point(786, 0);
|
||||
this.btn_Send.Name = "btn_Send";
|
||||
this.btn_Send.Size = new System.Drawing.Size(86, 25);
|
||||
this.btn_Send.TabIndex = 1;
|
||||
this.btn_Send.Text = "发送";
|
||||
this.btn_Send.UseVisualStyleBackColor = true;
|
||||
this.btn_Send.Click += new System.EventHandler(this.btn_Send_Click);
|
||||
//
|
||||
// splitter1
|
||||
//
|
||||
this.splitter1.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.splitter1.Location = new System.Drawing.Point(0, 382);
|
||||
this.splitter1.Name = "splitter1";
|
||||
this.splitter1.Size = new System.Drawing.Size(872, 10);
|
||||
this.splitter1.TabIndex = 9;
|
||||
this.splitter1.TabStop = false;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.richTextBox1);
|
||||
this.groupBox2.Controls.Add(this.dataGridView1);
|
||||
this.groupBox2.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.groupBox2.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.groupBox2.Location = new System.Drawing.Point(0, 392);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(872, 222);
|
||||
this.groupBox2.TabIndex = 8;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "接收:";
|
||||
//
|
||||
// richTextBox1
|
||||
//
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.richTextBox1.Location = new System.Drawing.Point(3, 25);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.Size = new System.Drawing.Size(866, 194);
|
||||
this.richTextBox1.TabIndex = 5;
|
||||
this.richTextBox1.Text = "";
|
||||
//
|
||||
// dataGridView1
|
||||
//
|
||||
this.dataGridView1.AllowUserToAddRows = false;
|
||||
this.dataGridView1.BackgroundColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dataGridView1.GridColor = System.Drawing.Color.Snow;
|
||||
this.dataGridView1.Location = new System.Drawing.Point(3, 25);
|
||||
this.dataGridView1.MultiSelect = false;
|
||||
this.dataGridView1.Name = "dataGridView1";
|
||||
this.dataGridView1.ReadOnly = true;
|
||||
this.dataGridView1.RowHeadersVisible = false;
|
||||
this.dataGridView1.RowHeadersWidth = 4;
|
||||
this.dataGridView1.RowTemplate.Height = 23;
|
||||
this.dataGridView1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dataGridView1.Size = new System.Drawing.Size(866, 194);
|
||||
this.dataGridView1.TabIndex = 0;
|
||||
//
|
||||
// Device
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(872, 639);
|
||||
this.Controls.Add(this.splitter1);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.panel1);
|
||||
this.Name = "Device";
|
||||
this.Text = "Device";
|
||||
this.Load += new System.EventHandler(this.Device_Load);
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv_devices)).EndInit();
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.DataGridView dgv_devices;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.TextBox txt_Send;
|
||||
private System.Windows.Forms.Button btn_Send;
|
||||
private System.Windows.Forms.Splitter splitter1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||
private System.Windows.Forms.DataGridView dataGridView1;
|
||||
}
|
||||
}
|
||||
188
UdpPlugWebsocket/Device/Device.cs
Normal file
188
UdpPlugWebsocket/Device/Device.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Miuser.NUDP.Sockets;
|
||||
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
public partial class Device : Form
|
||||
{
|
||||
string s_output;
|
||||
|
||||
//本UDP服务对象
|
||||
public SocketServer server;
|
||||
//人工选中的连接对象
|
||||
public SocketConnection curr;
|
||||
|
||||
|
||||
public Device()
|
||||
{
|
||||
InitializeComponent();
|
||||
server = new SocketServer(SetupForm.cfg.UDPPort);
|
||||
//处理从客户端收到的消息
|
||||
server.HandleRecMsg = new Action<byte[], SocketConnection, SocketServer>((bytes, client, theServer) =>
|
||||
{
|
||||
string msg = Encoding.UTF8.GetString(bytes);
|
||||
SetOutput(client.Tag+$" 收到消息:{msg}");
|
||||
});
|
||||
|
||||
//处理服务器启动后事件
|
||||
server.HandleServerStarted = new Action<SocketServer>(theServer =>
|
||||
{
|
||||
LogMessage("UDP Server 服务已启动************");
|
||||
});
|
||||
|
||||
//处理新的客户端连接后的事件
|
||||
server.HandleNewClientConnected = new Action<SocketServer, SocketConnection>((theServer, theCon) =>
|
||||
{
|
||||
LogMessage(theCon.Tag+ $@" UDP客户端接入,当前连接数:{theServer.GetConnectionCount()}");
|
||||
RefreshDataGrid(theServer);
|
||||
|
||||
});
|
||||
|
||||
//处理客户端连接关闭后的事件
|
||||
server.HandleClientClose = new Action<SocketConnection, SocketServer>((theCon, theServer) =>
|
||||
{
|
||||
LogMessage(theCon.Tag + $@" UDP客户端关闭,当前连接数为:{theServer.GetConnectionCount()}");
|
||||
RefreshDataGrid(theServer);
|
||||
|
||||
});
|
||||
|
||||
//处理异常
|
||||
server.HandleException = new Action<Exception>(ex =>
|
||||
{
|
||||
LogError(ex.Message+" "+ex.StackTrace);
|
||||
});
|
||||
server.StartServer();
|
||||
|
||||
}
|
||||
private void Device_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void RefreshDataGrid(SocketServer theServer)
|
||||
{
|
||||
DataTable dt = GetConnectionTable(theServer);
|
||||
lock (dt)
|
||||
{
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
dgv_devices.DataSource = dt;
|
||||
dgv_devices.Columns[0].Width = 200;
|
||||
}));
|
||||
}
|
||||
}
|
||||
private DataTable GetConnectionTable(SocketServer server)
|
||||
{
|
||||
DataTable dt = new DataTable();
|
||||
dt.Columns.Add("Tag");
|
||||
dt.Columns.Add("IP");
|
||||
dt.Columns.Add("UDP");
|
||||
dt.Columns.Add("Lifetime");
|
||||
|
||||
IEnumerable<SocketConnection> connections = server.GetConnectionList();
|
||||
lock (connections)
|
||||
{
|
||||
foreach (SocketConnection conn in server.GetConnectionList().ToArray())
|
||||
{
|
||||
DataRow dr = dt.NewRow();
|
||||
dr[0] = conn.Tag;
|
||||
dr[1] = conn._endpoint.Address;
|
||||
dr[2] = conn._endpoint.Port;
|
||||
dr[3] = conn._lifetime;
|
||||
dt.Rows.Add(dr);
|
||||
}
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
private static Device _instance;
|
||||
public static Device Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new Device();
|
||||
return _instance;
|
||||
}
|
||||
private set { _instance = value; }
|
||||
}
|
||||
|
||||
|
||||
private void btn_Send_Click(object sender, EventArgs e)
|
||||
{
|
||||
curr?.Send(txt_Send.Text);
|
||||
}
|
||||
|
||||
private void dgv_devices_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (dgv_devices.SelectedRows.Count > 0)
|
||||
{
|
||||
string tag = dgv_devices.SelectedRows[0].Cells["Tag"].Value.ToString();
|
||||
curr = server.GetTheConnection(x =>
|
||||
{
|
||||
var Id = (string)x.Tag;
|
||||
return Id == tag;
|
||||
});
|
||||
}else
|
||||
{
|
||||
curr = null;
|
||||
}
|
||||
}
|
||||
public void LogMessage(string message)
|
||||
{
|
||||
HandleMessage?.Invoke(message);
|
||||
}
|
||||
public void LogError(string message)
|
||||
{
|
||||
HandleError?.Invoke(message);
|
||||
}
|
||||
#region 消息和错误事件
|
||||
/// <summary>
|
||||
/// 消息处理程序
|
||||
/// </summary>
|
||||
public Action<string> HandleMessage { get; set; }
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<string> HandleError { get; set; }
|
||||
#endregion
|
||||
public void SetOutput(string text)
|
||||
{
|
||||
//决定是否屏显
|
||||
if (SetupForm.cfg.EnableScreenLog==false) return;
|
||||
|
||||
text = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + " |" + text;
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
s_output = s_output + text.Replace("\0", "") + "\r";
|
||||
|
||||
if ((s_output.Length) > 5000)
|
||||
{
|
||||
s_output = s_output.Substring(s_output.Length - 5000, 5000);
|
||||
}
|
||||
//滚到最后
|
||||
this.richTextBox1.Text = s_output;
|
||||
this.richTextBox1.Select(richTextBox1.TextLength, 0);
|
||||
//this.richTextBox1.Focus();
|
||||
this.richTextBox1.ScrollToCaret();
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
private void groupBox1_Enter(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
120
UdpPlugWebsocket/Device/Device.resx
Normal file
120
UdpPlugWebsocket/Device/Device.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
241
UdpPlugWebsocket/Device/SocketClient.cs
Normal file
241
UdpPlugWebsocket/Device/SocketClient.cs
Normal file
@@ -0,0 +1,241 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace Coldairarrow.Util.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket客户端
|
||||
/// </summary>
|
||||
public class SocketClient
|
||||
{
|
||||
#region 构造函数
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数,连接服务器IP地址默认为本机127.0.0.1
|
||||
/// </summary>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public SocketClient(int port)
|
||||
{
|
||||
_ip = "127.0.0.1";
|
||||
_port = port;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">监听的IP地址</param>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public SocketClient(string ip, int port)
|
||||
{
|
||||
_ip = ip;
|
||||
_port = port;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 内部成员
|
||||
|
||||
private Socket _socket = null;
|
||||
private string _ip = "";
|
||||
private int _port = 0;
|
||||
private bool _isRec=true;
|
||||
private bool IsSocketConnected()
|
||||
{
|
||||
bool part1 = _socket.Poll(1000, SelectMode.SelectRead);
|
||||
bool part2 = (_socket.Available == 0);
|
||||
if (part1 && part2)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始接受客户端消息
|
||||
/// </summary>
|
||||
public void StartRecMsg()
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] container = new byte[1024 * 1024 * 2];
|
||||
_socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int length = _socket.EndReceive(asyncResult);
|
||||
|
||||
//马上进行下一轮接受,增加吞吐量
|
||||
if (length > 0 && _isRec && IsSocketConnected())
|
||||
StartRecMsg();
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
byte[] recBytes = new byte[length];
|
||||
Array.Copy(container, 0, recBytes, 0, length);
|
||||
|
||||
//处理消息
|
||||
HandleRecMsg?.BeginInvoke(recBytes, this,null,null);
|
||||
}
|
||||
else
|
||||
Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
Close();
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 外部接口
|
||||
|
||||
/// <summary>
|
||||
/// 开始服务,连接服务端
|
||||
/// </summary>
|
||||
public void StartClient()
|
||||
{
|
||||
try
|
||||
{
|
||||
//实例化 套接字 (ip4寻址协议,流式传输,TCP协议)
|
||||
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
//创建 ip对象
|
||||
IPAddress address = IPAddress.Parse(_ip);
|
||||
//创建网络节点对象 包含 ip和port
|
||||
IPEndPoint endpoint = new IPEndPoint(address, _port);
|
||||
//将 监听套接字 绑定到 对应的IP和端口
|
||||
_socket.BeginConnect(endpoint, asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket.EndConnect(asyncResult);
|
||||
//开始接受服务器消息
|
||||
StartRecMsg();
|
||||
|
||||
HandleClientStarted?.BeginInvoke(this,null,null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据
|
||||
/// </summary>
|
||||
/// <param name="bytes">数据字节</param>
|
||||
public void Send(byte[] bytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int length = _socket.EndSend(asyncResult);
|
||||
HandleSendMsg?.BeginInvoke(bytes, this,null,null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字符串(默认使用UTF-8编码)
|
||||
/// </summary>
|
||||
/// <param name="msgStr">字符串</param>
|
||||
public void Send(string msgStr)
|
||||
{
|
||||
Send(Encoding.UTF8.GetBytes(msgStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字符串(使用自定义编码)
|
||||
/// </summary>
|
||||
/// <param name="msgStr">字符串消息</param>
|
||||
/// <param name="encoding">使用的编码</param>
|
||||
public void Send(string msgStr, Encoding encoding)
|
||||
{
|
||||
Send(encoding.GetBytes(msgStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 传入自定义属性
|
||||
/// </summary>
|
||||
public object Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关闭与服务器的连接
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isRec = false;
|
||||
_socket.Disconnect(false);
|
||||
HandleClientClose?.BeginInvoke(this,null,null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex,null,null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_socket.Dispose();
|
||||
GC.Collect();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 事件处理
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接建立后回调
|
||||
/// </summary>
|
||||
public Action<SocketClient> HandleClientStarted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理接受消息的委托
|
||||
/// </summary>
|
||||
public Action<byte[], SocketClient> HandleRecMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接发送消息后回调
|
||||
/// </summary>
|
||||
public Action<byte[], SocketClient> HandleSendMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接关闭后回调
|
||||
/// </summary>
|
||||
public Action<SocketClient> HandleClientClose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
153
UdpPlugWebsocket/Device/SocketConnection.cs
Normal file
153
UdpPlugWebsocket/Device/SocketConnection.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using UdpPlugWebsocket;
|
||||
|
||||
namespace Miuser.NUDP.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket连接,双向通信
|
||||
/// </summary>
|
||||
public class SocketConnection
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="socket">维护的Socket对象</param>
|
||||
/// <param name="server">维护此连接的服务对象</param>
|
||||
public SocketConnection(IPEndPoint endpoint,SocketServer server)
|
||||
{
|
||||
_endpoint = endpoint;
|
||||
_server = server;
|
||||
InitTimer();
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
#region 私有成员
|
||||
//UDP连接生存时间
|
||||
private static int LIFELIMIT =SetupForm.cfg.UDPTTL;
|
||||
//定义Timer类
|
||||
private System.Timers.Timer timer;
|
||||
#endregion
|
||||
#region 内部函数
|
||||
/// <summary>
|
||||
/// 初始化Timer控件
|
||||
/// </summary>
|
||||
private void InitTimer()
|
||||
{
|
||||
//设置定时间隔(毫秒为单位)
|
||||
int interval = 1000;
|
||||
timer = new System.Timers.Timer(interval);
|
||||
//设置执行一次(false)还是一直执行(true)
|
||||
timer.AutoReset = true;
|
||||
//设置是否执行System.Timers.Timer.Elapsed事件
|
||||
timer.Enabled = true;
|
||||
//绑定Elapsed事件
|
||||
timer.Elapsed += new System.Timers.ElapsedEventHandler(TimerUp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timer类执行定时到点事件
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void TimerUp(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
_lifetime -= (int)((System.Timers.Timer)(sender)).Interval;
|
||||
if (_lifetime <= 0)
|
||||
{
|
||||
IsActive = false;
|
||||
HandleClientClose?.Invoke(this, _server);
|
||||
timer.Dispose();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 公有成员
|
||||
//连接字符
|
||||
public readonly IPEndPoint _endpoint;
|
||||
//服务端
|
||||
public SocketServer _server = null;
|
||||
//剩余生存时间
|
||||
public int _lifetime = LIFELIMIT;
|
||||
#endregion
|
||||
|
||||
#region 外部接口
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据
|
||||
/// </summary>
|
||||
/// <param name="bytes">数据字节</param>
|
||||
public void Send(byte[] bytes)
|
||||
{
|
||||
if (_server == null) return;
|
||||
try
|
||||
{
|
||||
_server._socket.SendTo(bytes, _endpoint);
|
||||
HandleSendMsg?.Invoke(bytes,this, _server);
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字符串(默认使用UTF-8编码)
|
||||
/// </summary>
|
||||
/// <param name="msgStr">字符串</param>
|
||||
public void Send(string msgStr)
|
||||
{
|
||||
Send(Encoding.UTF8.GetBytes(msgStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字符串(使用自定义编码)
|
||||
/// </summary>
|
||||
/// <param name="msgStr">字符串消息</param>
|
||||
/// <param name="encoding">使用的编码</param>
|
||||
public void Send(string msgStr,Encoding encoding)
|
||||
{
|
||||
Send(encoding.GetBytes(msgStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 传入自定义属性
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接是否仍然活着
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; }
|
||||
/// <summary>
|
||||
/// 重新激活连接,连接生命加满
|
||||
/// </summary>
|
||||
public void Reactive()
|
||||
{
|
||||
_lifetime = LIFELIMIT;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 事件处理
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接发送消息后回调
|
||||
/// </summary>
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接关闭后回调
|
||||
/// </summary>
|
||||
public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
369
UdpPlugWebsocket/Device/SocketServer.cs
Normal file
369
UdpPlugWebsocket/Device/SocketServer.cs
Normal file
@@ -0,0 +1,369 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Data;
|
||||
namespace Miuser.NUDP.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket服务端
|
||||
/// </summary>
|
||||
public class SocketServer
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="ip">监听的IP地址</param>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public SocketServer(string ip, int port)
|
||||
{
|
||||
_ip = ip;
|
||||
_port = port;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数,监听IP地址默认为本机0.0.0.0
|
||||
/// </summary>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public SocketServer(int port)
|
||||
{
|
||||
_ip = "0.0.0.0";
|
||||
_port = port;
|
||||
//处理客户端连接关闭后的事件
|
||||
Instance = this;
|
||||
|
||||
}
|
||||
#region 内部成员
|
||||
|
||||
private string _ip { get; set; } = "";
|
||||
private int _port { get; set; } = 0;
|
||||
private bool _isListen { get; set; } = true;
|
||||
|
||||
private LinkedList<SocketConnection> _clientList { get; } = new LinkedList<SocketConnection>();
|
||||
|
||||
internal class UdpState
|
||||
{
|
||||
public byte[] Buffer;
|
||||
public EndPoint Remote;
|
||||
public Socket Socket;
|
||||
public UdpState()
|
||||
{
|
||||
Buffer = new byte[65536];
|
||||
}
|
||||
}
|
||||
private bool IsListening { get; set; }
|
||||
#endregion
|
||||
#region 外部成员
|
||||
/// <summary>
|
||||
/// 指向本类的静态对象,对象为最近生成的类实例
|
||||
/// </summary>
|
||||
/// <param name="port">监听的端口</param>
|
||||
public static SocketServer Instance;
|
||||
public Socket _socket { get; set; } = null;
|
||||
#endregion
|
||||
|
||||
#region 内部函数
|
||||
/// <summary>
|
||||
/// 删除指定的客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
private void RemoveConnection(SocketConnection theConnection)
|
||||
{
|
||||
RWLock_ClientList.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_clientList.Remove(theConnection);
|
||||
HandleClientClose?.Invoke(theConnection, this);
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除不活动的客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
private void RemoveInactiveConnections()
|
||||
{
|
||||
List<SocketConnection> conns = new List<SocketConnection>();
|
||||
foreach (SocketConnection connect in _clientList.ToArray())
|
||||
{
|
||||
if (connect.IsActive == false)
|
||||
{
|
||||
conns.Add(connect);
|
||||
}
|
||||
}
|
||||
foreach (SocketConnection conn in conns.ToArray())
|
||||
{
|
||||
RemoveInactiveConnection(conn);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 检测该客户端,如果不活动则删除连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
private void RemoveInactiveConnection(SocketConnection connect)
|
||||
{
|
||||
if (connect.IsActive == false)
|
||||
{
|
||||
RemoveConnection(connect);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 当某连接不活动超时激活该函数
|
||||
/// </summary>
|
||||
private void HandleConnClientClose(SocketConnection conn, SocketServer server)
|
||||
{
|
||||
RemoveConnection(conn);
|
||||
}
|
||||
/// <summary>
|
||||
/// 维护客户端列表的读写锁
|
||||
/// </summary>
|
||||
private ReaderWriterLockSlim RWLock_ClientList { get; } = new ReaderWriterLockSlim();
|
||||
private void EndReceiveFrom(IAsyncResult ir)
|
||||
{
|
||||
if (IsListening)
|
||||
{
|
||||
UdpState state = ir.AsyncState as UdpState;
|
||||
try
|
||||
{
|
||||
if (ir.IsCompleted)
|
||||
{
|
||||
int length = state.Socket.EndReceiveFrom(ir, ref state.Remote);
|
||||
byte[] btReceived = new byte[length];
|
||||
Buffer.BlockCopy(state.Buffer, 0, btReceived, 0, length);
|
||||
|
||||
//查询是否UDP连接已经存在
|
||||
SocketConnection connection = GetTheConnection(x =>
|
||||
{
|
||||
var Id = (string)x.Tag;
|
||||
return Id == state.Remote.ToString();
|
||||
});
|
||||
//如果不存在则新建一个UDP连接对象
|
||||
if (connection == null)
|
||||
{
|
||||
connection = new SocketConnection(state.Remote as IPEndPoint, this)
|
||||
{
|
||||
HandleSendMsg = HandleSendMsg == null ? null : new Action<byte[], SocketConnection, SocketServer>(HandleSendMsg),
|
||||
HandleClientClose = new Action<SocketConnection, SocketServer>(HandleConnClientClose),
|
||||
HandleException = HandleException == null ? null : new Action<Exception>(HandleException)
|
||||
};
|
||||
|
||||
//connection.HandleClientClose += HandleClientClose == null ? null : new Action<SocketConnection, SocketServer>(HandleClientClose);
|
||||
|
||||
connection.Tag = state.Remote.ToString();
|
||||
AddConnection(connection);
|
||||
|
||||
}
|
||||
connection.Reactive();
|
||||
HandleRecMsg?.Invoke(btReceived, connection, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString() + "\t" + ex.Message + ex.Source);
|
||||
HandleException?.Invoke(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
state.Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.Remote, new AsyncCallback(EndReceiveFrom), state);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 关闭指定客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
#endregion
|
||||
|
||||
|
||||
#region 外部接口
|
||||
/// <summary>
|
||||
/// 开始服务,监听客户端
|
||||
/// </summary>
|
||||
public void StartServer()
|
||||
{
|
||||
try
|
||||
{
|
||||
//实例化套接字(ip4寻址协议,流式传输,TCP协议)
|
||||
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
//开始侦听
|
||||
Listening();
|
||||
HandleServerStarted?.BeginInvoke(this, null, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex, null, null);
|
||||
}
|
||||
}
|
||||
///<summary>
|
||||
///按照IP地址和端口发送字符串
|
||||
///</summary>
|
||||
public void Send(string EndpointString, byte[] bytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
SocketConnection conn = GetTheConnection(x =>
|
||||
{
|
||||
var Id = (string)x.Tag;
|
||||
return Id == EndpointString;
|
||||
});
|
||||
conn.Send(bytes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException?.BeginInvoke(ex, null, null);
|
||||
}
|
||||
}
|
||||
///<summary>
|
||||
///开始异步监听端口
|
||||
///</summary>
|
||||
public void Listening()
|
||||
{
|
||||
IPAddress ip = IPAddress.Any;
|
||||
try
|
||||
{
|
||||
if (this._ip != null)
|
||||
if (!IPAddress.TryParse(this._ip, out ip))
|
||||
throw new ArgumentException("IP地址错误", "Ip");
|
||||
_socket.Bind(new IPEndPoint(ip, this._port));
|
||||
|
||||
UdpState state = new UdpState();
|
||||
state.Socket = _socket;
|
||||
state.Remote = new IPEndPoint(IPAddress.Any, 0);
|
||||
_socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.Remote, new AsyncCallback(EndReceiveFrom), state);
|
||||
|
||||
IsListening = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsListening = false;
|
||||
HandleException?.BeginInvoke(ex, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 异步处理收到的数据包
|
||||
/// </summary>
|
||||
|
||||
public void CloseConnection(SocketConnection theConnection)
|
||||
{
|
||||
RemoveConnection(theConnection);
|
||||
//调用外部回调函数通知连接被关闭
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">需要添加的客户端连接</param>
|
||||
public void AddConnection(SocketConnection theConnection)
|
||||
{
|
||||
RWLock_ClientList.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_clientList.AddLast(theConnection);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitWriteLock();
|
||||
//调用外部回调函数通知新连接建立
|
||||
HandleNewClientConnected(this, theConnection);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 通过条件获取客户端连接列表
|
||||
/// </summary>
|
||||
/// <param name="predicate">筛选条件</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SocketConnection> GetConnectionList(Func<SocketConnection, bool> predicate)
|
||||
{
|
||||
|
||||
RemoveInactiveConnections();
|
||||
IEnumerable<SocketConnection> ret;
|
||||
lock (_clientList)
|
||||
{
|
||||
ret = _clientList.Where(predicate);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取所有客户端连接列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SocketConnection> GetConnectionList()
|
||||
{
|
||||
RemoveInactiveConnections();
|
||||
return _clientList;
|
||||
}
|
||||
/// <summary>
|
||||
/// 寻找特定条件的客户端连接
|
||||
/// </summary>
|
||||
/// <param name="predicate">筛选条件</param>
|
||||
/// <returns></returns>
|
||||
public SocketConnection GetTheConnection(Func<SocketConnection, bool> predicate)
|
||||
{
|
||||
SocketConnection conn;
|
||||
lock (_clientList)
|
||||
{
|
||||
conn = _clientList.Where(predicate).FirstOrDefault();
|
||||
}
|
||||
if (conn == null) return null;
|
||||
|
||||
RemoveInactiveConnection(conn);
|
||||
|
||||
if (conn.IsActive) return conn;
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取客户端连接数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetConnectionCount()
|
||||
{
|
||||
int ret;
|
||||
lock (_clientList)
|
||||
{
|
||||
ret = _clientList.Count;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 服务端事件
|
||||
/// <summary>
|
||||
/// 服务启动后执行
|
||||
/// </summary>
|
||||
public Action<SocketServer> HandleServerStarted { get; set; }
|
||||
#endregion
|
||||
#region 客户端连接事件
|
||||
/// <summary>
|
||||
/// 当新客户端连接后执行
|
||||
/// </summary>
|
||||
public Action<SocketServer, SocketConnection> HandleNewClientConnected { get; set; }
|
||||
/// <summary>
|
||||
/// 客户端连接接受新的消息后调用
|
||||
/// </summary>
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; }
|
||||
/// <summary>
|
||||
/// 客户端连接发送消息后回调
|
||||
/// </summary>
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }
|
||||
/// <summary>
|
||||
/// 客户端连接关闭后回调
|
||||
/// </summary>
|
||||
public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }
|
||||
#endregion
|
||||
#region 公共事件
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
43
UdpPlugWebsocket/Device/SocketServerEvent.cs
Normal file
43
UdpPlugWebsocket/Device/SocketServerEvent.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace Miuser.NUDP.Sockets
|
||||
{
|
||||
#region
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public class SocketExceptionEventArgs : EventArgs { public Exception Exception; public EndPoint Remote; }
|
||||
/// <summary>
|
||||
/// 服务启动后执行
|
||||
/// </summary>
|
||||
public class ServerStartedEventArgs : EventArgs { public EndPoint Server; }
|
||||
/// <summary>
|
||||
/// 服务端关闭客户端后执行
|
||||
/// </summary>
|
||||
public class ServerClosedEventArgs : EventArgs { public EndPoint Server; }
|
||||
/// <summary>
|
||||
/// 当新客户端连接后执行
|
||||
/// </summary>
|
||||
public class NewClientEventArgs : EventArgs { public EndPoint Remote; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接关闭后回调
|
||||
/// </summary>
|
||||
public class ClientClosedEventArgs : EventArgs { public EndPoint Remote; }
|
||||
/// <summary>
|
||||
/// 客户端连接接受新的消息后调用
|
||||
/// </summary>
|
||||
public class MsgReceivedEventArgs : EventArgs { public byte[] Received; public EndPoint Remote; }
|
||||
/// <summary>
|
||||
/// 客户端连接发送消息后回调
|
||||
/// </summary>
|
||||
public class MsgSendEventArgs : EventArgs { public byte[] Received; public EndPoint Remote; }
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
305
UdpPlugWebsocket/Form1.Designer.cs
generated
Normal file
305
UdpPlugWebsocket/Form1.Designer.cs
generated
Normal file
@@ -0,0 +1,305 @@
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
partial class Form1
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows 窗体设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.配置ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.系统配置ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.配置ToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.系统配置ToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.显示调试信息ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.硬件ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.pan_Left = new System.Windows.Forms.Panel();
|
||||
this.btn_Panel = new System.Windows.Forms.Button();
|
||||
this.btn_Browser = new System.Windows.Forms.Button();
|
||||
this.btn_Device = new System.Windows.Forms.Button();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.slab_bottom = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.pan_Fill = new System.Windows.Forms.Panel();
|
||||
this.splitter1 = new System.Windows.Forms.Splitter();
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tab_Message = new System.Windows.Forms.TabPage();
|
||||
this.tab_Error = new System.Windows.Forms.TabPage();
|
||||
this.pan_Top = new System.Windows.Forms.Panel();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.pan_Left.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.pan_Fill.SuspendLayout();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.配置ToolStripMenuItem,
|
||||
this.配置ToolStripMenuItem1,
|
||||
this.硬件ToolStripMenuItem});
|
||||
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip1.Name = "menuStrip1";
|
||||
this.menuStrip1.Size = new System.Drawing.Size(1121, 29);
|
||||
this.menuStrip1.TabIndex = 23;
|
||||
this.menuStrip1.Text = "mnu_Main";
|
||||
//
|
||||
// 配置ToolStripMenuItem
|
||||
//
|
||||
this.配置ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.系统配置ToolStripMenuItem});
|
||||
this.配置ToolStripMenuItem.Name = "配置ToolStripMenuItem";
|
||||
this.配置ToolStripMenuItem.Size = new System.Drawing.Size(12, 20);
|
||||
//
|
||||
// 系统配置ToolStripMenuItem
|
||||
//
|
||||
this.系统配置ToolStripMenuItem.Name = "系统配置ToolStripMenuItem";
|
||||
this.系统配置ToolStripMenuItem.Size = new System.Drawing.Size(124, 22);
|
||||
this.系统配置ToolStripMenuItem.Text = "系统配置";
|
||||
//
|
||||
// 配置ToolStripMenuItem1
|
||||
//
|
||||
this.配置ToolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.系统配置ToolStripMenuItem1,
|
||||
this.exitToolStripMenuItem,
|
||||
this.显示调试信息ToolStripMenuItem});
|
||||
this.配置ToolStripMenuItem1.Font = new System.Drawing.Font("新宋体", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.配置ToolStripMenuItem1.Name = "配置ToolStripMenuItem1";
|
||||
this.配置ToolStripMenuItem1.Size = new System.Drawing.Size(66, 25);
|
||||
this.配置ToolStripMenuItem1.Text = "配置";
|
||||
//
|
||||
// 系统配置ToolStripMenuItem1
|
||||
//
|
||||
this.系统配置ToolStripMenuItem1.Name = "系统配置ToolStripMenuItem1";
|
||||
this.系统配置ToolStripMenuItem1.Size = new System.Drawing.Size(158, 22);
|
||||
this.系统配置ToolStripMenuItem1.Text = "系统配置";
|
||||
this.系统配置ToolStripMenuItem1.Click += new System.EventHandler(this.系统配置ToolStripMenuItem1_Click);
|
||||
//
|
||||
// exitToolStripMenuItem
|
||||
//
|
||||
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||
this.exitToolStripMenuItem.Size = new System.Drawing.Size(158, 22);
|
||||
this.exitToolStripMenuItem.Text = "退出";
|
||||
this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
|
||||
//
|
||||
// 显示调试信息ToolStripMenuItem
|
||||
//
|
||||
this.显示调试信息ToolStripMenuItem.Name = "显示调试信息ToolStripMenuItem";
|
||||
this.显示调试信息ToolStripMenuItem.Size = new System.Drawing.Size(158, 22);
|
||||
this.显示调试信息ToolStripMenuItem.Text = "显示调试信息";
|
||||
this.显示调试信息ToolStripMenuItem.Click += new System.EventHandler(this.显示调试信息ToolStripMenuItem_Click);
|
||||
//
|
||||
// 硬件ToolStripMenuItem
|
||||
//
|
||||
this.硬件ToolStripMenuItem.Font = new System.Drawing.Font("新宋体", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.硬件ToolStripMenuItem.Name = "硬件ToolStripMenuItem";
|
||||
this.硬件ToolStripMenuItem.Size = new System.Drawing.Size(66, 25);
|
||||
this.硬件ToolStripMenuItem.Text = "帮助";
|
||||
this.硬件ToolStripMenuItem.Click += new System.EventHandler(this.硬件ToolStripMenuItem_Click);
|
||||
//
|
||||
// pan_Left
|
||||
//
|
||||
this.pan_Left.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.pan_Left.Controls.Add(this.btn_Panel);
|
||||
this.pan_Left.Controls.Add(this.btn_Browser);
|
||||
this.pan_Left.Controls.Add(this.btn_Device);
|
||||
this.pan_Left.Dock = System.Windows.Forms.DockStyle.Left;
|
||||
this.pan_Left.Location = new System.Drawing.Point(0, 29);
|
||||
this.pan_Left.Name = "pan_Left";
|
||||
this.pan_Left.Size = new System.Drawing.Size(263, 613);
|
||||
this.pan_Left.TabIndex = 24;
|
||||
//
|
||||
// btn_Panel
|
||||
//
|
||||
this.btn_Panel.BackColor = System.Drawing.Color.White;
|
||||
this.btn_Panel.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.btn_Panel.Font = new System.Drawing.Font("微软雅黑", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.btn_Panel.Location = new System.Drawing.Point(0, 100);
|
||||
this.btn_Panel.Name = "btn_Panel";
|
||||
this.btn_Panel.Size = new System.Drawing.Size(261, 50);
|
||||
this.btn_Panel.TabIndex = 8;
|
||||
this.btn_Panel.Text = "交换面板";
|
||||
this.btn_Panel.UseVisualStyleBackColor = false;
|
||||
this.btn_Panel.Click += new System.EventHandler(this.btn_Panel_Click);
|
||||
//
|
||||
// btn_Browser
|
||||
//
|
||||
this.btn_Browser.BackColor = System.Drawing.Color.White;
|
||||
this.btn_Browser.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.btn_Browser.Font = new System.Drawing.Font("微软雅黑", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.btn_Browser.Location = new System.Drawing.Point(0, 50);
|
||||
this.btn_Browser.Name = "btn_Browser";
|
||||
this.btn_Browser.Size = new System.Drawing.Size(261, 50);
|
||||
this.btn_Browser.TabIndex = 6;
|
||||
this.btn_Browser.Text = "控制页面";
|
||||
this.btn_Browser.UseVisualStyleBackColor = false;
|
||||
this.btn_Browser.Click += new System.EventHandler(this.btn_Browser_Click);
|
||||
//
|
||||
// btn_Device
|
||||
//
|
||||
this.btn_Device.BackColor = System.Drawing.Color.White;
|
||||
this.btn_Device.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.btn_Device.Font = new System.Drawing.Font("微软雅黑", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.btn_Device.Location = new System.Drawing.Point(0, 0);
|
||||
this.btn_Device.Name = "btn_Device";
|
||||
this.btn_Device.Size = new System.Drawing.Size(261, 50);
|
||||
this.btn_Device.TabIndex = 5;
|
||||
this.btn_Device.Text = "终端设备";
|
||||
this.btn_Device.UseVisualStyleBackColor = false;
|
||||
this.btn_Device.Click += new System.EventHandler(this.btn_Device_Click);
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.slab_bottom});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 642);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Size = new System.Drawing.Size(1121, 22);
|
||||
this.statusStrip1.TabIndex = 60;
|
||||
this.statusStrip1.Text = "状态:";
|
||||
//
|
||||
// slab_bottom
|
||||
//
|
||||
this.slab_bottom.AutoSize = false;
|
||||
this.slab_bottom.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.slab_bottom.Name = "slab_bottom";
|
||||
this.slab_bottom.Size = new System.Drawing.Size(300, 17);
|
||||
this.slab_bottom.Text = "状态:";
|
||||
this.slab_bottom.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// pan_Fill
|
||||
//
|
||||
this.pan_Fill.BackColor = System.Drawing.Color.White;
|
||||
this.pan_Fill.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.pan_Fill.Controls.Add(this.splitter1);
|
||||
this.pan_Fill.Controls.Add(this.tabControl1);
|
||||
this.pan_Fill.Controls.Add(this.pan_Top);
|
||||
this.pan_Fill.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pan_Fill.Location = new System.Drawing.Point(263, 29);
|
||||
this.pan_Fill.Name = "pan_Fill";
|
||||
this.pan_Fill.Size = new System.Drawing.Size(858, 613);
|
||||
this.pan_Fill.TabIndex = 61;
|
||||
//
|
||||
// splitter1
|
||||
//
|
||||
this.splitter1.BackColor = System.Drawing.SystemColors.ActiveBorder;
|
||||
this.splitter1.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.splitter1.Location = new System.Drawing.Point(0, 507);
|
||||
this.splitter1.Name = "splitter1";
|
||||
this.splitter1.Size = new System.Drawing.Size(856, 2);
|
||||
this.splitter1.TabIndex = 8;
|
||||
this.splitter1.TabStop = false;
|
||||
//
|
||||
// tabControl1
|
||||
//
|
||||
this.tabControl1.Alignment = System.Windows.Forms.TabAlignment.Bottom;
|
||||
this.tabControl1.Controls.Add(this.tab_Message);
|
||||
this.tabControl1.Controls.Add(this.tab_Error);
|
||||
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabControl1.Location = new System.Drawing.Point(0, 507);
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(856, 104);
|
||||
this.tabControl1.TabIndex = 7;
|
||||
//
|
||||
// tab_Message
|
||||
//
|
||||
this.tab_Message.Location = new System.Drawing.Point(4, 4);
|
||||
this.tab_Message.Name = "tab_Message";
|
||||
this.tab_Message.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tab_Message.Size = new System.Drawing.Size(848, 78);
|
||||
this.tab_Message.TabIndex = 1;
|
||||
this.tab_Message.Text = "Message";
|
||||
this.tab_Message.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tab_Error
|
||||
//
|
||||
this.tab_Error.Location = new System.Drawing.Point(4, 4);
|
||||
this.tab_Error.Name = "tab_Error";
|
||||
this.tab_Error.Size = new System.Drawing.Size(848, 80);
|
||||
this.tab_Error.TabIndex = 2;
|
||||
this.tab_Error.Text = "Error";
|
||||
this.tab_Error.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// pan_Top
|
||||
//
|
||||
this.pan_Top.BackColor = System.Drawing.Color.White;
|
||||
this.pan_Top.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.pan_Top.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.pan_Top.Location = new System.Drawing.Point(0, 0);
|
||||
this.pan_Top.Name = "pan_Top";
|
||||
this.pan_Top.Size = new System.Drawing.Size(856, 507);
|
||||
this.pan_Top.TabIndex = 4;
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1121, 664);
|
||||
this.Controls.Add(this.pan_Fill);
|
||||
this.Controls.Add(this.pan_Left);
|
||||
this.Controls.Add(this.menuStrip1);
|
||||
this.Controls.Add(this.statusStrip1);
|
||||
this.Name = "Form1";
|
||||
this.Text = "UdpPlugWebsocket 0.1";
|
||||
this.Load += new System.EventHandler(this.Form1_Load);
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.pan_Left.ResumeLayout(false);
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.pan_Fill.ResumeLayout(false);
|
||||
this.tabControl1.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem 配置ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem 系统配置ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem 配置ToolStripMenuItem1;
|
||||
private System.Windows.Forms.ToolStripMenuItem 系统配置ToolStripMenuItem1;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem 硬件ToolStripMenuItem;
|
||||
private System.Windows.Forms.Panel pan_Left;
|
||||
private System.Windows.Forms.Button btn_Panel;
|
||||
private System.Windows.Forms.Button btn_Browser;
|
||||
private System.Windows.Forms.Button btn_Device;
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel slab_bottom;
|
||||
private System.Windows.Forms.Panel pan_Fill;
|
||||
private System.Windows.Forms.Splitter splitter1;
|
||||
private System.Windows.Forms.TabControl tabControl1;
|
||||
private System.Windows.Forms.TabPage tab_Error;
|
||||
private System.Windows.Forms.TabPage tab_Message;
|
||||
public System.Windows.Forms.Panel pan_Top;
|
||||
private System.Windows.Forms.ToolStripMenuItem 显示调试信息ToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
|
||||
176
UdpPlugWebsocket/Form1.cs
Normal file
176
UdpPlugWebsocket/Form1.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
public partial class Form1 : Form
|
||||
{
|
||||
//所有窗体的容器
|
||||
List<Form> forms = new List<Form>();
|
||||
|
||||
//初始化配置窗体
|
||||
SetupForm setup = new SetupForm();
|
||||
|
||||
//初始化所有窗体对象,每个窗体对应一个功能模组
|
||||
private void Init_Forms()
|
||||
{
|
||||
try
|
||||
{
|
||||
//添加终端设备窗体
|
||||
forms.Add(Device.Instance);
|
||||
//添加浏览器窗体
|
||||
forms.Add(Browser.Instance);
|
||||
//添加交换面板窗体
|
||||
forms.Add(Panel.Instance);
|
||||
|
||||
//配置窗体为子窗体,并添加到主窗体上
|
||||
foreach (Form frm in forms)
|
||||
{
|
||||
frm.TopLevel = false;
|
||||
frm.FormBorderStyle = FormBorderStyle.None;
|
||||
frm.Dock = DockStyle.Fill;
|
||||
pan_Top.Controls.Add(frm);
|
||||
}
|
||||
|
||||
tab_Message.Controls.Add(MessageForm.Instance);
|
||||
MessageForm.Instance.Show();
|
||||
|
||||
tab_Error.Controls.Add(ErrorForm.Instance);
|
||||
ErrorForm.Instance.Show();
|
||||
|
||||
//连接模块与系统终端窗口
|
||||
Device.Instance.HandleMessage += new Action<string>(MessageForm.Log);
|
||||
Device.Instance.HandleError += new Action<string>(ErrorForm.Log);
|
||||
|
||||
Browser.Instance.HandleMessage += new Action<string>(MessageForm.Log);
|
||||
Browser.Instance.HandleError += new Action<string>(ErrorForm.Log);
|
||||
//连接Pannel数据输入端 Device->Panel
|
||||
Device.Instance.server.HandleRecMsg += new Action<byte[], Miuser.NUDP.Sockets.SocketConnection, Miuser.NUDP.Sockets.SocketServer>((bytes, conn, server) =>
|
||||
{
|
||||
Panel.Instance.sw.SendFromUDP(bytes, conn.Tag.ToString());
|
||||
});
|
||||
//连接Pannel数据输入端 Browser->Panel
|
||||
Browser.Instance.HandleWebSocketRecMsg += new Action<byte[], WebSocketSharp.Net.WebSockets.WebSocketContext>((bytes, context) =>
|
||||
{
|
||||
Panel.Instance.sw.SendFromWebSocket(bytes, context.UserEndPoint.ToString());
|
||||
});
|
||||
//连接Pannel数据输出端 Panel->Device
|
||||
Panel.Instance.sw.HandleUDPSendMsg += new Action<byte[], string>((bytes, endpointString) =>
|
||||
{
|
||||
Device.Instance.server.Send(endpointString, bytes);
|
||||
});
|
||||
//连接Panel数据输出端 Panel->Browser
|
||||
Panel.Instance.sw.HandleWebSocketSendMsg += new Action<byte[], string>((bytes, endpointString)=>
|
||||
{
|
||||
Browser.Instance.Send(endpointString, bytes);
|
||||
});
|
||||
|
||||
//刷新菜单状态
|
||||
显示调试信息ToolStripMenuItem.Checked = SetupForm.cfg.EnableScreenLog;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.StackTrace,"系统模块初始化错误");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//使所有子窗体不可见
|
||||
private void Invislble_Forms()
|
||||
{
|
||||
foreach (Form frm in forms)
|
||||
{
|
||||
frm.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
//根据类名获得窗体对象
|
||||
private Form Get_Form(string className)
|
||||
{
|
||||
foreach (Form frm in forms)
|
||||
{
|
||||
if (frm.GetType().Name == className)
|
||||
{
|
||||
return frm;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private void ShowModule(string moduleName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Get_Form(moduleName) != null) Get_Form(moduleName).Visible = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.StackTrace, "系统模块初始化错误");
|
||||
}
|
||||
}
|
||||
public Form1()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Form1_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
Init_Forms();
|
||||
ShowModule("Device");
|
||||
}
|
||||
|
||||
private void btn_Device_Click(object sender, EventArgs e)
|
||||
{
|
||||
Invislble_Forms();
|
||||
ShowModule("Device");
|
||||
|
||||
}
|
||||
|
||||
private void btn_Browser_Click(object sender, EventArgs e)
|
||||
{
|
||||
{
|
||||
Invislble_Forms();
|
||||
ShowModule("Browser");
|
||||
}
|
||||
}
|
||||
|
||||
private void btn_Panel_Click(object sender, EventArgs e)
|
||||
{
|
||||
Invislble_Forms();
|
||||
ShowModule("Panel");
|
||||
}
|
||||
|
||||
private void 系统配置ToolStripMenuItem1_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
setup.ShowDialog();
|
||||
}
|
||||
|
||||
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
System.Environment.Exit(0);
|
||||
}
|
||||
|
||||
private void 硬件ToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
MessageBox.Show("UPW 0.1 \n Tks Song");
|
||||
}
|
||||
|
||||
private void btn_LogScreen_Click(object sender, EventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
private void 显示调试信息ToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
SetupForm.cfg.EnableScreenLog = !SetupForm.cfg.EnableScreenLog;
|
||||
显示调试信息ToolStripMenuItem.Checked = SetupForm.cfg.EnableScreenLog;
|
||||
}
|
||||
}
|
||||
}
|
||||
129
UdpPlugWebsocket/Form1.resx
Normal file
129
UdpPlugWebsocket/Form1.resx
Normal file
@@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>259, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>55</value>
|
||||
</metadata>
|
||||
</root>
|
||||
60
UdpPlugWebsocket/Message/ErrorForm.Designer.cs
generated
Normal file
60
UdpPlugWebsocket/Message/ErrorForm.Designer.cs
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
partial class ErrorForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// richTextBox1
|
||||
//
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.Size = new System.Drawing.Size(463, 400);
|
||||
this.richTextBox1.TabIndex = 0;
|
||||
this.richTextBox1.Text = "";
|
||||
//
|
||||
// Message
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(463, 400);
|
||||
this.Controls.Add(this.richTextBox1);
|
||||
this.Name = "Message";
|
||||
this.Text = "Message";
|
||||
this.Load += new System.EventHandler(this.Message_Load);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||
}
|
||||
}
|
||||
81
UdpPlugWebsocket/Message/ErrorForm.cs
Normal file
81
UdpPlugWebsocket/Message/ErrorForm.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
public partial class ErrorForm : Form
|
||||
{
|
||||
private ErrorForm()
|
||||
{
|
||||
//窗体子窗口化
|
||||
this.TopLevel = false;
|
||||
this.FormBorderStyle = FormBorderStyle.None;
|
||||
this.Dock = DockStyle.Fill;
|
||||
InitializeComponent();
|
||||
Instance = this;
|
||||
this.FormClosed += Message_FormClosed;
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void Message_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
private static ErrorForm _instance;
|
||||
|
||||
public static ErrorForm Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new ErrorForm();
|
||||
return _instance;
|
||||
}
|
||||
private set { _instance = value; }
|
||||
}
|
||||
|
||||
String s_output = "";
|
||||
public void SetOutput(string text)
|
||||
{
|
||||
text = DateTime.Now.ToLongDateString() +" "+DateTime.Now.ToLongTimeString()+ " " + text;
|
||||
Action action = () =>
|
||||
{
|
||||
s_output = s_output + text + "\r";
|
||||
|
||||
if ((s_output.Length)>5000)
|
||||
{
|
||||
s_output = s_output.Substring(s_output.Length - 5000, 5000);
|
||||
}
|
||||
//滚到最后
|
||||
this.richTextBox1.Text = s_output;
|
||||
this.richTextBox1.Select(richTextBox1.TextLength, 0);
|
||||
//this.richTextBox1.Focus();
|
||||
this.richTextBox1.ScrollToCaret();
|
||||
|
||||
};
|
||||
|
||||
this.richTextBox1.Invoke(action);
|
||||
}
|
||||
|
||||
public static void Log(string text)
|
||||
{
|
||||
if (_instance != null)
|
||||
{
|
||||
_instance.SetOutput(text);
|
||||
}
|
||||
}
|
||||
|
||||
private void Message_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
120
UdpPlugWebsocket/Message/ErrorForm.resx
Normal file
120
UdpPlugWebsocket/Message/ErrorForm.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
60
UdpPlugWebsocket/Message/MessageForm.Designer.cs
generated
Normal file
60
UdpPlugWebsocket/Message/MessageForm.Designer.cs
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
partial class MessageForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// richTextBox1
|
||||
//
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.Size = new System.Drawing.Size(463, 400);
|
||||
this.richTextBox1.TabIndex = 0;
|
||||
this.richTextBox1.Text = "";
|
||||
this.richTextBox1.TextChanged += new System.EventHandler(this.richTextBox1_TextChanged);
|
||||
//
|
||||
// MessageForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.richTextBox1);
|
||||
this.Name = "MessageForm";
|
||||
this.Size = new System.Drawing.Size(463, 400);
|
||||
this.Load += new System.EventHandler(this.Log_Load);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||
}
|
||||
}
|
||||
85
UdpPlugWebsocket/Message/MessageForm.cs
Normal file
85
UdpPlugWebsocket/Message/MessageForm.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
public partial class MessageForm : Form
|
||||
{
|
||||
private MessageForm()
|
||||
{
|
||||
//打开添加用户面板
|
||||
this.TopLevel = false;
|
||||
this.FormBorderStyle = FormBorderStyle.None;
|
||||
this.Dock = DockStyle.Fill;
|
||||
InitializeComponent();
|
||||
Instance = this;
|
||||
this.FormClosed += Log_FormClosed;
|
||||
|
||||
}
|
||||
private void Log_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
private static MessageForm _instance;
|
||||
|
||||
public static MessageForm Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new MessageForm();
|
||||
return _instance;
|
||||
}
|
||||
private set { _instance = value; }
|
||||
}
|
||||
|
||||
String s_output = "";
|
||||
public void SetOutput(string text)
|
||||
{
|
||||
//决定是否屏显
|
||||
if (SetupForm.cfg.EnableScreenLog == false) return;
|
||||
|
||||
text = DateTime.Now.ToLongDateString() +" "+DateTime.Now.ToLongTimeString()+ " " + text;
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
s_output = s_output + text.Replace("\0", "") + "\r";
|
||||
|
||||
if ((s_output.Length) > 5000)
|
||||
{
|
||||
s_output = s_output.Substring(s_output.Length - 5000, 5000);
|
||||
}
|
||||
//滚到最后
|
||||
this.richTextBox1.Text = s_output;
|
||||
this.richTextBox1.Select(richTextBox1.TextLength, 0);
|
||||
//this.richTextBox1.Focus();
|
||||
this.richTextBox1.ScrollToCaret();
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Log(string text)
|
||||
{
|
||||
if (_instance != null)
|
||||
{
|
||||
_instance.SetOutput(text);
|
||||
}
|
||||
}
|
||||
|
||||
private void Log_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void richTextBox1_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
120
UdpPlugWebsocket/Message/MessageForm.resx
Normal file
120
UdpPlugWebsocket/Message/MessageForm.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
269
UdpPlugWebsocket/Panel/Node.cs
Normal file
269
UdpPlugWebsocket/Panel/Node.cs
Normal file
@@ -0,0 +1,269 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
public class WSConnection
|
||||
{
|
||||
//Websocket连接生存时间
|
||||
private static int LIFELIMIT = SetupForm.cfg.NODETTL;
|
||||
public string EndpointString;
|
||||
public int ttl;
|
||||
//定义Timer类
|
||||
private System.Timers.Timer timer;
|
||||
public WSConnection()
|
||||
{
|
||||
System.Timers.Timer timer = new System.Timers.Timer();
|
||||
ttl = LIFELIMIT;
|
||||
InitTimer();
|
||||
IsActive = true;
|
||||
}
|
||||
#region 内部函数
|
||||
/// <summary>
|
||||
/// 初始化Timer控件
|
||||
/// </summary>
|
||||
private void InitTimer()
|
||||
{
|
||||
//设置定时间隔(毫秒为单位)
|
||||
int interval = 1000;
|
||||
timer = new System.Timers.Timer(interval);
|
||||
//设置执行一次(false)还是一直执行(true)
|
||||
timer.AutoReset = true;
|
||||
//设置是否执行System.Timers.Timer.Elapsed事件
|
||||
timer.Enabled = true;
|
||||
//绑定Elapsed事件
|
||||
timer.Elapsed += new System.Timers.ElapsedEventHandler(TimerUp);
|
||||
}
|
||||
/// <summary>
|
||||
/// Timer类执行定时到点事件
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void TimerUp(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
ttl -= (int)((System.Timers.Timer)(sender)).Interval;
|
||||
if (ttl <= 0)
|
||||
{
|
||||
IsActive = false;
|
||||
HandleWebsocketClosed?.Invoke(this);
|
||||
timer.Dispose();
|
||||
}
|
||||
}
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public void Reactive()
|
||||
{
|
||||
ttl = LIFELIMIT;
|
||||
}
|
||||
#endregion
|
||||
#region 事件处理
|
||||
/// <summary>
|
||||
/// NODE关闭后回调
|
||||
/// </summary>
|
||||
public Action<WSConnection> HandleWebsocketClosed { get; set; }
|
||||
#endregion
|
||||
}
|
||||
public class UDPConnection
|
||||
{
|
||||
//UDP连接生存时间
|
||||
private static int LIFELIMIT = SetupForm.cfg.NODETTL;
|
||||
public string EndpointString;
|
||||
public int ttl;
|
||||
//定义Timer类
|
||||
private System.Timers.Timer timer;
|
||||
public UDPConnection()
|
||||
{
|
||||
System.Timers.Timer timer = new System.Timers.Timer();
|
||||
ttl = LIFELIMIT;
|
||||
InitTimer();
|
||||
IsActive = true;
|
||||
}
|
||||
#region 内部函数
|
||||
/// <summary>
|
||||
/// 初始化Timer控件
|
||||
/// </summary>
|
||||
private void InitTimer()
|
||||
{
|
||||
//设置定时间隔(毫秒为单位)
|
||||
int interval = 1000;
|
||||
timer = new System.Timers.Timer(interval);
|
||||
//设置执行一次(false)还是一直执行(true)
|
||||
timer.AutoReset = true;
|
||||
//设置是否执行System.Timers.Timer.Elapsed事件
|
||||
timer.Enabled = true;
|
||||
//绑定Elapsed事件
|
||||
timer.Elapsed += new System.Timers.ElapsedEventHandler(TimerUp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timer类执行定时到点事件
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void TimerUp(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
ttl -= (int)((System.Timers.Timer)(sender)).Interval;
|
||||
if (ttl <= 0)
|
||||
{
|
||||
IsActive = false;
|
||||
HandleUDPClosed?.Invoke(this);
|
||||
timer.Dispose();
|
||||
}
|
||||
}
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public void Reactive()
|
||||
{
|
||||
ttl = LIFELIMIT;
|
||||
}
|
||||
#endregion
|
||||
#region 事件处理
|
||||
|
||||
/// <summary>
|
||||
/// NODE关闭后回调
|
||||
/// </summary>
|
||||
public Action<UDPConnection> HandleUDPClosed { get; set; }
|
||||
#endregion
|
||||
}
|
||||
|
||||
//交换模块的群组
|
||||
public class NODE
|
||||
{
|
||||
//NODE连接生存时间
|
||||
private static int LIFELIMIT = SetupForm.cfg.NODETTL;
|
||||
//剩余生存时间
|
||||
public int ttl;
|
||||
//节点的UID
|
||||
public string ID;
|
||||
|
||||
public List<WSConnection> WebsocketConnections;
|
||||
public List<UDPConnection> UDPConnections;
|
||||
|
||||
//定义Timer类
|
||||
private System.Timers.Timer timer;
|
||||
|
||||
|
||||
public NODE(string ID)
|
||||
{
|
||||
WebsocketConnections = new List<WSConnection>();
|
||||
UDPConnections = new List<UDPConnection>();
|
||||
System.Timers.Timer timer = new System.Timers.Timer();
|
||||
ttl = LIFELIMIT;
|
||||
InitTimer();
|
||||
IsActive = true;
|
||||
HandleNodeCreated?.Invoke(this);
|
||||
|
||||
}
|
||||
#region 内部函数
|
||||
/// <summary>
|
||||
/// 初始化Timer控件
|
||||
/// </summary>
|
||||
private void InitTimer()
|
||||
{
|
||||
//设置定时间隔(毫秒为单位)
|
||||
int interval = 1000;
|
||||
timer = new System.Timers.Timer(interval);
|
||||
//设置执行一次(false)还是一直执行(true)
|
||||
timer.AutoReset = true;
|
||||
//设置是否执行System.Timers.Timer.Elapsed事件
|
||||
timer.Enabled = true;
|
||||
//绑定Elapsed事件
|
||||
timer.Elapsed += new System.Timers.ElapsedEventHandler(TimerUp);
|
||||
}
|
||||
/// <summary>
|
||||
/// Timer类执行定时到点事件
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void TimerUp(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
ttl -= (int)((System.Timers.Timer)(sender)).Interval;
|
||||
if (ttl <= 0)
|
||||
{
|
||||
IsActive = false;
|
||||
HandleNodeClosed?.Invoke(this);
|
||||
timer.Dispose();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
# region 外部函数
|
||||
public void AddSource(string endpoint, Switch.Source source)
|
||||
{
|
||||
if (source == Switch.Source.UDPPort) AddUDPConnection(endpoint);
|
||||
if (source == Switch.Source.WebSocket) AddWebsocketConnection(endpoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个新的UDP连接
|
||||
/// </summary>
|
||||
/// <param name="endpoint"></param>
|
||||
public void AddUDPConnection(string endpoint)
|
||||
{
|
||||
UDPConnection udp = new UDPConnection();
|
||||
udp.EndpointString = endpoint;
|
||||
//节点超时则自动从连接中移除
|
||||
udp.HandleUDPClosed = new Action<UDPConnection>((conn => {
|
||||
UDPConnections.Remove(conn); HandleUDPRemoved?.Invoke(conn.EndpointString);
|
||||
}));
|
||||
UDPConnections.Add(udp);
|
||||
HandleUDPAdded?.Invoke(endpoint);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加一个新的Websocket连接
|
||||
/// </summary>
|
||||
/// <param name="endpoint"></param>
|
||||
public void AddWebsocketConnection(string endpoint)
|
||||
{
|
||||
WSConnection web = new WSConnection();
|
||||
web.EndpointString = endpoint;
|
||||
//节点超时则自动从连接中移除
|
||||
web.HandleWebsocketClosed = new Action<WSConnection>((conn => {
|
||||
WebsocketConnections.Remove(conn); HandleWebSocketRemoved?.Invoke(conn.EndpointString);
|
||||
}));
|
||||
WebsocketConnections.Add(web);
|
||||
HandleWebSocketAdded?.Invoke(endpoint);
|
||||
}
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public void Reactive()
|
||||
{
|
||||
ttl = LIFELIMIT;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 事件处理
|
||||
/// <summary>
|
||||
/// NODE关闭后回调
|
||||
/// </summary>
|
||||
public Action<NODE> HandleNodeClosed { get; set; }
|
||||
/// <summary>
|
||||
/// NODE建立后回调
|
||||
/// </summary>
|
||||
public Action<NODE> HandleNodeCreated { get; set; }
|
||||
/// <summary>
|
||||
/// 新的Websocket连接建立后回调
|
||||
/// </summary>
|
||||
public Action<string> HandleWebSocketAdded { get; set; }
|
||||
/// <summary>
|
||||
/// 新的Websocket连接断开后回调
|
||||
/// </summary>
|
||||
public Action<string> HandleWebSocketRemoved { get; set; }
|
||||
/// <summary>
|
||||
/// 新的UDP连接建立后回调
|
||||
/// </summary>
|
||||
public Action<string> HandleUDPAdded { get; set; }
|
||||
/// <summary>
|
||||
/// 新的UDP连接断开后回调
|
||||
/// </summary>
|
||||
public Action<string> HandleUDPRemoved { get; set; }
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
149
UdpPlugWebsocket/Panel/Panel.Designer.cs
generated
Normal file
149
UdpPlugWebsocket/Panel/Panel.Designer.cs
generated
Normal file
@@ -0,0 +1,149 @@
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
partial class Panel
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.dataGridView1 = new System.Windows.Forms.DataGridView();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.dgv_nodes = new System.Windows.Forms.DataGridView();
|
||||
this.splitter1 = new System.Windows.Forms.Splitter();
|
||||
this.groupBox2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
|
||||
this.groupBox1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv_nodes)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.richTextBox1);
|
||||
this.groupBox2.Controls.Add(this.dataGridView1);
|
||||
this.groupBox2.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.groupBox2.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.groupBox2.Location = new System.Drawing.Point(0, 394);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(685, 222);
|
||||
this.groupBox2.TabIndex = 5;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "会话:";
|
||||
//
|
||||
// richTextBox1
|
||||
//
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.richTextBox1.Location = new System.Drawing.Point(3, 25);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.Size = new System.Drawing.Size(679, 194);
|
||||
this.richTextBox1.TabIndex = 5;
|
||||
this.richTextBox1.Text = "";
|
||||
//
|
||||
// dataGridView1
|
||||
//
|
||||
this.dataGridView1.AllowUserToAddRows = false;
|
||||
this.dataGridView1.BackgroundColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dataGridView1.GridColor = System.Drawing.Color.Snow;
|
||||
this.dataGridView1.Location = new System.Drawing.Point(3, 25);
|
||||
this.dataGridView1.MultiSelect = false;
|
||||
this.dataGridView1.Name = "dataGridView1";
|
||||
this.dataGridView1.ReadOnly = true;
|
||||
this.dataGridView1.RowHeadersVisible = false;
|
||||
this.dataGridView1.RowHeadersWidth = 4;
|
||||
this.dataGridView1.RowTemplate.Height = 23;
|
||||
this.dataGridView1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dataGridView1.Size = new System.Drawing.Size(679, 194);
|
||||
this.dataGridView1.TabIndex = 0;
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.dgv_nodes);
|
||||
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.groupBox1.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.groupBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(685, 384);
|
||||
this.groupBox1.TabIndex = 3;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "节点:";
|
||||
//
|
||||
// dgv_nodes
|
||||
//
|
||||
this.dgv_nodes.AllowUserToAddRows = false;
|
||||
this.dgv_nodes.BackgroundColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.dgv_nodes.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dgv_nodes.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dgv_nodes.GridColor = System.Drawing.Color.Snow;
|
||||
this.dgv_nodes.Location = new System.Drawing.Point(3, 25);
|
||||
this.dgv_nodes.MultiSelect = false;
|
||||
this.dgv_nodes.Name = "dgv_nodes";
|
||||
this.dgv_nodes.ReadOnly = true;
|
||||
this.dgv_nodes.RowHeadersVisible = false;
|
||||
this.dgv_nodes.RowHeadersWidth = 4;
|
||||
this.dgv_nodes.RowTemplate.Height = 23;
|
||||
this.dgv_nodes.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dgv_nodes.Size = new System.Drawing.Size(679, 356);
|
||||
this.dgv_nodes.TabIndex = 1;
|
||||
//
|
||||
// splitter1
|
||||
//
|
||||
this.splitter1.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.splitter1.Location = new System.Drawing.Point(0, 384);
|
||||
this.splitter1.Name = "splitter1";
|
||||
this.splitter1.Size = new System.Drawing.Size(685, 10);
|
||||
this.splitter1.TabIndex = 7;
|
||||
this.splitter1.TabStop = false;
|
||||
//
|
||||
// Panel
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(685, 616);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.splitter1);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Name = "Panel";
|
||||
this.Text = "Panel";
|
||||
this.Load += new System.EventHandler(this.Panel_Load);
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv_nodes)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||
private System.Windows.Forms.DataGridView dataGridView1;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.Splitter splitter1;
|
||||
private System.Windows.Forms.DataGridView dgv_nodes;
|
||||
}
|
||||
}
|
||||
142
UdpPlugWebsocket/Panel/Panel.cs
Normal file
142
UdpPlugWebsocket/Panel/Panel.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Miuser.NUDP.Sockets;
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
public partial class Panel : Form
|
||||
{
|
||||
//交换机的实例
|
||||
public Switch sw;
|
||||
public Panel()
|
||||
{
|
||||
InitializeComponent();
|
||||
sw = new Switch();
|
||||
//处理新的结点连接后的事件
|
||||
sw.HandleNodeCreated = new Action<Switch, NODE>((theSW, theNode) =>
|
||||
{
|
||||
//RefreshDataGrid(theSW);
|
||||
});
|
||||
//处理节点关闭后的事件
|
||||
sw.HandleNodeClosed = new Action<Switch, NODE>((theSW, theNode) =>
|
||||
{
|
||||
//RefreshDataGrid(theSW);
|
||||
});
|
||||
//处理节点状态变化后的事件
|
||||
sw.HandleNodeChanged = new Action<Switch, NODE>((theSW, theNode) =>
|
||||
{
|
||||
RefreshDataGrid(theSW);
|
||||
});
|
||||
//节点接收UDP消息后的事件
|
||||
sw.HandleUDPRsvMsg = new Action<byte[], string>((bytes, endpointString) =>
|
||||
{
|
||||
SetOutput("(UDP " + endpointString + ")<=" + System.Text.Encoding.Default.GetString(bytes));
|
||||
});
|
||||
//节点收到Websocket消息后的事件
|
||||
sw.HandleWebsocketRsvMsg = new Action<byte[], string>((bytes, endpointString) =>
|
||||
{
|
||||
SetOutput("(WebSocket " + endpointString + ")<=" + System.Text.Encoding.Default.GetString(bytes));
|
||||
});
|
||||
|
||||
//节点发送UDP消息后的事件
|
||||
sw.HandleUDPSendMsg = new Action<byte[], string>((bytes, endpointString) =>
|
||||
{
|
||||
SetOutput("(UDP " + endpointString + ")=>" + System.Text.Encoding.Default.GetString(bytes));
|
||||
});
|
||||
//节点发送Websocket消息后的事件
|
||||
sw.HandleWebSocketSendMsg = new Action<byte[], string>((bytes, endpointString) =>
|
||||
{
|
||||
SetOutput("(WebSocket " + endpointString + ")=>" + System.Text.Encoding.Default.GetString(bytes));
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
private static Panel _instance;
|
||||
public static Panel Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new Panel();
|
||||
return _instance;
|
||||
}
|
||||
private set { _instance = value; }
|
||||
}
|
||||
|
||||
private void Panel_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void RefreshDataGrid(Switch theSw)
|
||||
{
|
||||
DataTable dt = GetNodeTable(theSw);
|
||||
lock (dt)
|
||||
{
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
dgv_nodes.DataSource = dt;
|
||||
dgv_nodes.Columns[0].Width = 150;
|
||||
dgv_nodes.Columns[1].Width = 100;
|
||||
dgv_nodes.Columns[2].Width = 100;
|
||||
}));
|
||||
}
|
||||
}
|
||||
private DataTable GetNodeTable(Switch theSw)
|
||||
{
|
||||
DataTable dt = new DataTable();
|
||||
dt.Columns.Add("ID");
|
||||
dt.Columns.Add("UDP ");
|
||||
dt.Columns.Add("Websocket");
|
||||
dt.Columns.Add("Lifetime");
|
||||
|
||||
IEnumerable<NODE> nodes = theSw.GetNodeList();
|
||||
lock (nodes)
|
||||
{
|
||||
foreach (NODE node in theSw.GetNodeList().ToArray())
|
||||
{
|
||||
DataRow dr = dt.NewRow();
|
||||
dr[0] = node.ID;
|
||||
dr[1] = node.UDPConnections==null? 0:node.UDPConnections.Count;
|
||||
dr[2] = node.WebsocketConnections == null ? 0 : node.WebsocketConnections.Count;
|
||||
dr[3] = node.ttl;
|
||||
dt.Rows.Add(dr);
|
||||
}
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
String s_output = "";
|
||||
public void SetOutput(string text)
|
||||
{
|
||||
//决定是否屏显
|
||||
if (SetupForm.cfg.EnableScreenLog == false) return;
|
||||
text = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + " |" + text;
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
s_output = s_output + text.Replace("\0", "") + "\r";
|
||||
|
||||
if ((s_output.Length) > 5000)
|
||||
{
|
||||
s_output = s_output.Substring(s_output.Length - 5000, 5000);
|
||||
}
|
||||
//滚到最后
|
||||
this.richTextBox1.Text = s_output;
|
||||
this.richTextBox1.Select(richTextBox1.TextLength, 0);
|
||||
//this.richTextBox1.Focus();
|
||||
this.richTextBox1.ScrollToCaret();
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
120
UdpPlugWebsocket/Panel/Panel.resx
Normal file
120
UdpPlugWebsocket/Panel/Panel.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
389
UdpPlugWebsocket/Panel/Switch.cs
Normal file
389
UdpPlugWebsocket/Panel/Switch.cs
Normal file
@@ -0,0 +1,389 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using Miuser.NUDP.Sockets;
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
public class Switch
|
||||
{
|
||||
//存储以ID为
|
||||
public List<NODE> nodes;
|
||||
|
||||
public Switch()
|
||||
{
|
||||
nodes = new List<NODE>();
|
||||
}
|
||||
/// <summary>
|
||||
/// 接收来自UDP的数据并进行转发
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="EndpointString"></param>
|
||||
public void SendFromUDP(byte[] bytes, string EndpointString)
|
||||
{
|
||||
HandleUDPRsvMsg?.Invoke(bytes, EndpointString);
|
||||
string content = System.Text.Encoding.Default.GetString(bytes);
|
||||
string ID = "";
|
||||
if (content.Length >= 19)
|
||||
{
|
||||
ID = content.Substring(9, 10);
|
||||
NODE node = GetTheNode((x =>
|
||||
{
|
||||
var Id = (string)x.ID;
|
||||
return Id == ID;
|
||||
}));
|
||||
//如果不存在则新建一个NODE
|
||||
if (node == null)
|
||||
{
|
||||
node = new NODE(ID)
|
||||
{
|
||||
//连接Node消息到Switch上
|
||||
HandleNodeClosed = HandleNodeClosed == null ? null : new Action<NODE>((nod) => { HandleNodeClosed(this, nod); }),
|
||||
HandleNodeCreated = HandleNodeCreated == null ? null : new Action<NODE>((nod) => { HandleNodeCreated(this, nod); }),
|
||||
HandleUDPAdded = new Action<string>(target =>
|
||||
{
|
||||
HandleNodeChanged?.Invoke(this, node);
|
||||
}),
|
||||
HandleUDPRemoved = new Action<string>(target =>
|
||||
{
|
||||
HandleNodeChanged?.Invoke(this, node);
|
||||
}),
|
||||
HandleWebSocketAdded = new Action<string>(target =>
|
||||
{
|
||||
HandleNodeChanged?.Invoke(this, node);
|
||||
}),
|
||||
HandleWebSocketRemoved= new Action<string>(target =>
|
||||
{
|
||||
HandleNodeChanged?.Invoke(this, node);
|
||||
}),
|
||||
HandleException=new Action<Exception>(ex=>
|
||||
{
|
||||
HandleException(ex);
|
||||
})
|
||||
};
|
||||
node.ID = ID;
|
||||
AddNode(node);
|
||||
}
|
||||
|
||||
//判断连接是否为新连接,如果是则增加消息源
|
||||
if (node.UDPConnections.Where(x => { return EndpointString == x.EndpointString; }).FirstOrDefault() == null)
|
||||
{
|
||||
node.AddUDPConnection(EndpointString);
|
||||
}
|
||||
else
|
||||
{
|
||||
node.UDPConnections.Where(x => { return EndpointString == x.EndpointString; }).FirstOrDefault().Reactive();
|
||||
}
|
||||
node.Reactive();
|
||||
//分发消息给所有在线的Websocket端口
|
||||
lock (node.WebsocketConnections)
|
||||
{
|
||||
foreach (WSConnection ws in node.WebsocketConnections.ToArray())
|
||||
{
|
||||
HandleWebSocketSendMsg?.Invoke(bytes, ws.EndpointString);
|
||||
}
|
||||
}
|
||||
//分发消息给所有在线的UDP端口
|
||||
lock (node.UDPConnections)
|
||||
{
|
||||
foreach (UDPConnection udp in node.UDPConnections.ToArray())
|
||||
{
|
||||
HandleUDPSendMsg?.Invoke(bytes, udp.EndpointString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SendFromWebSocket(byte[] bytes, string EndpointString)
|
||||
{
|
||||
HandleWebsocketRsvMsg?.Invoke(bytes, EndpointString);
|
||||
string content = System.Text.Encoding.Default.GetString(bytes);
|
||||
string ID = "";
|
||||
if (content.Length >= 19)
|
||||
{
|
||||
ID = content.Substring(9, 10);
|
||||
NODE node = GetTheNode((x =>
|
||||
{
|
||||
var Id = (string)x.ID;
|
||||
return Id == ID;
|
||||
}));
|
||||
//如果不存在则新建一个NODE
|
||||
if (node == null)
|
||||
{
|
||||
node = new NODE(ID)
|
||||
{
|
||||
//连接Node消息到Switch上
|
||||
HandleNodeClosed = HandleNodeClosed == null ? null : new Action<NODE>((nod) => { HandleNodeClosed(this, nod); }),
|
||||
HandleNodeCreated = HandleNodeCreated == null ? null : new Action<NODE>((nod) => { HandleNodeCreated(this, nod); }),
|
||||
HandleUDPAdded = new Action<string>(target =>
|
||||
{
|
||||
HandleNodeChanged?.Invoke(this, node);
|
||||
}),
|
||||
HandleUDPRemoved = new Action<string>(target =>
|
||||
{
|
||||
HandleNodeChanged?.Invoke(this, node);
|
||||
}),
|
||||
HandleWebSocketAdded = new Action<string>(target =>
|
||||
{
|
||||
HandleNodeChanged?.Invoke(this, node);
|
||||
}),
|
||||
HandleWebSocketRemoved= new Action<string>(target =>
|
||||
{
|
||||
HandleNodeChanged?.Invoke(this, node);
|
||||
}),
|
||||
HandleException=new Action<Exception>(ex=>
|
||||
{
|
||||
HandleException(ex);
|
||||
})
|
||||
|
||||
};
|
||||
node.ID = ID;
|
||||
AddNode(node);
|
||||
|
||||
}
|
||||
|
||||
//判断连接是否为新连接,如果是则增加消息源
|
||||
if (node.WebsocketConnections.Where(x => { return EndpointString == x.EndpointString; }).FirstOrDefault() == null)
|
||||
{
|
||||
node.AddWebsocketConnection(EndpointString);
|
||||
}else
|
||||
{
|
||||
node.WebsocketConnections.Where(x => { return EndpointString == x.EndpointString; }).FirstOrDefault().Reactive();
|
||||
}
|
||||
node.Reactive();
|
||||
|
||||
//分发消息给所有在线的Websocket端口
|
||||
if (node.WebsocketConnections != null)
|
||||
{
|
||||
lock (node.WebsocketConnections)
|
||||
{
|
||||
foreach (WSConnection ws in node.WebsocketConnections.ToArray())
|
||||
{
|
||||
HandleWebSocketSendMsg?.Invoke(bytes, ws.EndpointString);
|
||||
}
|
||||
}
|
||||
}
|
||||
//分发消息给所有在线的UDP端口
|
||||
if (node.UDPConnections != null)
|
||||
{
|
||||
lock (node.UDPConnections)
|
||||
{
|
||||
foreach (UDPConnection udp in node.UDPConnections.ToArray())
|
||||
{
|
||||
HandleUDPSendMsg?.Invoke(bytes, udp.EndpointString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region 内部函数
|
||||
private void RemoveNode(NODE node)
|
||||
{
|
||||
RWLock_ClientList.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
nodes.Remove(node);
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除不活动的客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
private void RemoveInactiveNodes()
|
||||
{
|
||||
List<NODE> nodes = new List<NODE>();
|
||||
foreach (NODE node in nodes.ToArray())
|
||||
{
|
||||
if (node.IsActive == false)
|
||||
{
|
||||
nodes.Add(node);
|
||||
}
|
||||
}
|
||||
foreach (NODE node in nodes.ToArray())
|
||||
{
|
||||
RemoveInactiveNode(node);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 检测该客户端,如果不活动则删除连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
private void RemoveInactiveNode(NODE node)
|
||||
{
|
||||
if (node.IsActive == false)
|
||||
{
|
||||
RemoveNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当某连接不活动超时激活该函数
|
||||
/// </summary>
|
||||
private void HandleConnClientClose(NODE node)
|
||||
{
|
||||
RemoveNode(node);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 维护客户端列表的读写锁
|
||||
/// </summary>
|
||||
public ReaderWriterLockSlim RWLock_ClientList { get; } = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// 关闭指定客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">指定的客户端连接</param>
|
||||
public void CloseNode(NODE node)
|
||||
{
|
||||
RemoveNode(node);
|
||||
//调用外部回调函数通知连接被关闭
|
||||
HandleNodeClosed?.Invoke(this,node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加客户端连接
|
||||
/// </summary>
|
||||
/// <param name="theConnection">需要添加的客户端连接</param>
|
||||
public enum Source {UDPPort,WebSocket }
|
||||
public void AddNode(NODE node)
|
||||
{
|
||||
RWLock_ClientList.EnterWriteLock();
|
||||
|
||||
try
|
||||
{
|
||||
nodes.Add(node);
|
||||
node.HandleNodeClosed = new Action<NODE>((id => { nodes.Remove(id); }));
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
RWLock_ClientList.ExitWriteLock();
|
||||
//调用外部回调函数通知新连接建立
|
||||
HandleNodeCreated?.Invoke(this, node);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过条件获取客户端连接列表
|
||||
/// </summary>
|
||||
/// <param name="predicate">筛选条件</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<NODE> GetNodeList(Func<NODE, bool> predicate)
|
||||
{
|
||||
|
||||
//RemoveInactiveNodes();
|
||||
IEnumerable<NODE> ret;
|
||||
lock (nodes)
|
||||
{
|
||||
ret = nodes.Where(predicate);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有客户端连接列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<NODE> GetNodeList()
|
||||
{
|
||||
//RemoveInactiveNodes();
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 寻找特定条件的客户端连接
|
||||
/// </summary>
|
||||
/// <param name="predicate">筛选条件</param>
|
||||
/// <returns></returns>
|
||||
public NODE GetTheNode(Func<NODE, bool> predicate)
|
||||
{
|
||||
NODE node;
|
||||
lock (nodes)
|
||||
{
|
||||
node = nodes.Where(predicate).FirstOrDefault();
|
||||
}
|
||||
if (node == null) return null;
|
||||
//RemoveInactiveNode(node);
|
||||
|
||||
if (node.IsActive) return node;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取客户端连接数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetConnectionCount()
|
||||
{
|
||||
int ret;
|
||||
lock (nodes)
|
||||
{
|
||||
ret = nodes.Count;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region UDP客户端连接事件
|
||||
|
||||
/// <summary>
|
||||
// 从UDP端口接收到消息
|
||||
/// </summary>
|
||||
public Action<byte[], string> HandleUDPRsvMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
// 转发消息给UDP端口
|
||||
/// </summary>
|
||||
public Action<byte[], string> HandleUDPSendMsg { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Websocket客户端连接事件
|
||||
|
||||
/// <summary>
|
||||
// 从Websocket端口接收到消息
|
||||
/// </summary>
|
||||
public Action<byte[], string> HandleWebsocketRsvMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 转发消息给Websocket端口
|
||||
/// </summary>
|
||||
public Action<byte[], string> HandleWebSocketSendMsg { get; set; }
|
||||
#endregion
|
||||
|
||||
#region 客户端连接事件
|
||||
/// <summary>
|
||||
/// 当新NODE建立后执行
|
||||
/// </summary>
|
||||
public Action<Switch,NODE> HandleNodeCreated { get; set; }
|
||||
/// <summary>
|
||||
/// NODE关闭后回调
|
||||
/// </summary>
|
||||
public Action<Switch,NODE> HandleNodeClosed { get; set; }
|
||||
/// <summary>
|
||||
/// 异常处理程序
|
||||
/// </summary>
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
/// <summary>
|
||||
/// 节点状态发生变化
|
||||
/// </summary>
|
||||
public Action<Switch, NODE> HandleNodeChanged { get; set; }
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
22
UdpPlugWebsocket/Program.cs
Normal file
22
UdpPlugWebsocket/Program.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点。
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new Form1());
|
||||
}
|
||||
}
|
||||
}
|
||||
36
UdpPlugWebsocket/Properties/AssemblyInfo.cs
Normal file
36
UdpPlugWebsocket/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("DoorControl")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DoorControl")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//将 ComVisible 设置为 false 将使此程序集中的类型
|
||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("54cf701b-b076-4fc3-8a01-7434111a1c5b")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
63
UdpPlugWebsocket/Properties/Resources.Designer.cs
generated
Normal file
63
UdpPlugWebsocket/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace UdpPlugWebsocket.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UdpPlugWebsocket.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用此强类型资源类,为所有资源查找
|
||||
/// 重写当前线程的 CurrentUICulture 属性。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
UdpPlugWebsocket/Properties/Resources.resx
Normal file
117
UdpPlugWebsocket/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
26
UdpPlugWebsocket/Properties/Settings.Designer.cs
generated
Normal file
26
UdpPlugWebsocket/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace UdpPlugWebsocket.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
UdpPlugWebsocket/Properties/Settings.settings
Normal file
7
UdpPlugWebsocket/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
60
UdpPlugWebsocket/ReadMe.md
Normal file
60
UdpPlugWebsocket/ReadMe.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# UdpPlugWebSocket 简称UPWS服务端程序#
|
||||
|
||||
|
||||
## 项目说明 ##
|
||||
|
||||
公司要做物联网硬件产品,需要一个服务器组件桥接APP软件终端和物联网硬件。 目前比较火的MQTT物联网协议虽然技术先进,但进入门槛较高,用户也相对较为复杂。BG了一番没有找到合适的服务端开源代码,就决定使用自己比较熟悉的.Net技术从头开发一个服务器组件。又考虑到自己毕竟是一个中国人没必要舍近求远的去用Git,就选择了在码云开了这个repository,如果能帮到你,我很高兴。 有问题欢迎与我微信联系: 微信号miuser00,加好友请注明您的来意。
|
||||
|
||||
## 项目简介 ##
|
||||
这是一个独立的可执行Win32服务端程序,用于桥接终端APP和物联网硬件。 APP端为Websocet接口的静态html页面,硬件端为基于Arduino开发的电路,与服务器通讯使用UDP协议通讯(注:为方便您的使用,本Respository亦提供了一个C#编写的简易UDP测试程序用来模拟硬件设备)。 APP通过Webscoket接口发送一个自定义的字符串报文给服务端,服务端根据报文中的ID把报文转发给相同ID的UDP硬件设备(或UDP测试程序)。
|
||||
|
||||

|
||||
|
||||
启动方法:在本地windows环境下运行.\UdpPlugWebsocket\bin\Debug\UdpPlugWebsocket.exe即可按照config.xml中描述的端口启动服务程序。默认UDP端口为7101,Websocket端口为9000。此时外部的UDP连接和Websocket连接都会在UI中显示。其中UDP在终端设备页面中显示,Websocket连接在控制页面中显示,通讯状况在交换面板页面中显示。您可以通过配置->显示调试系信息 打开或关闭UI的通讯Log。
|
||||
|
||||
|
||||
|
||||
|
||||
## 数据包格式 (UDP与Websocket相同)##
|
||||
|
||||

|
||||
|
||||
|
||||
**Endpoint是外部连接的唯一索引。**
|
||||
|
||||
**Endpoint字符串的格式为:"XXX.XXX.XXX.XXX:XXXX" 前四组三位数为IP地址,最后一组四位数为远程端口号**
|
||||
|
||||
##UDP通讯测试##
|
||||
|
||||
运行.\UdpExample\client\bin\Debug\client.exe 在程序控制台中输入如下数据包
|
||||
004832A08000000000200000000000000001234testtest05 即可在终端设备页面看到本机的连接。
|
||||

|
||||
## Websocket通讯测试 ##
|
||||
任意支持websocket的浏览器中运行.\UPW_Browser\index.html?ID=0000000002&MM=0000000000000000与UDP测试程序建立连接(参数区分大小写)
|
||||

|
||||
|
||||
## 目录结构 ##
|
||||
.\UdpPlugWebsocket UPWS服务程序(主服务程序)
|
||||
.\UdpPlugWebsocket\UdpExample UDP测试程序
|
||||
.\UPW_Browser Websocket测试程序
|
||||
.\bin_UPWS 编译后的Win32项目二进制文
|
||||
... 其余目录为参考代码目录,可删除
|
||||
|
||||
|
||||
##编译环境##
|
||||
Visual Studio 2015,C#,Win10
|
||||
|
||||
## 使用到的开源库 ##
|
||||
Websocket-Sharp
|
||||
https://github.com/sta/websocket-sharp
|
||||
Coldairarrow.Util.Sockets
|
||||
https://github.com/Coldairarrow/Sockets
|
||||
|
||||
|
||||
## 关键词 ##
|
||||
|
||||
C#,Websocket,UDP,物联网,异步编程,接口,lamda表达式,线程池,Action,Invoke,Arduino,ESP8266
|
||||
|
||||
## 版权声明 ##
|
||||
|
||||
如果您愿意使用 UdpPlugWebSocket 组件,请遵循 MIT 许可所述内容.
|
||||
88
UdpPlugWebsocket/UI/setup.Designer.cs
generated
Normal file
88
UdpPlugWebsocket/UI/setup.Designer.cs
generated
Normal file
@@ -0,0 +1,88 @@
|
||||
namespace UserLogin
|
||||
{
|
||||
partial class SetupForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btn_save = new System.Windows.Forms.Button();
|
||||
this.prg_config = new System.Windows.Forms.PropertyGrid();
|
||||
this.button1 = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btn_save
|
||||
//
|
||||
this.btn_save.Location = new System.Drawing.Point(443, 641);
|
||||
this.btn_save.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.btn_save.Name = "btn_save";
|
||||
this.btn_save.Size = new System.Drawing.Size(178, 30);
|
||||
this.btn_save.TabIndex = 3;
|
||||
this.btn_save.Text = "保存并重启";
|
||||
this.btn_save.UseVisualStyleBackColor = true;
|
||||
this.btn_save.Click += new System.EventHandler(this.btn_save_Click);
|
||||
//
|
||||
// prg_config
|
||||
//
|
||||
this.prg_config.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.prg_config.Location = new System.Drawing.Point(0, 0);
|
||||
this.prg_config.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.prg_config.Name = "prg_config";
|
||||
this.prg_config.Size = new System.Drawing.Size(663, 684);
|
||||
this.prg_config.TabIndex = 2;
|
||||
//
|
||||
// button1
|
||||
//
|
||||
this.button1.Location = new System.Drawing.Point(106, 641);
|
||||
this.button1.Name = "button1";
|
||||
this.button1.Size = new System.Drawing.Size(97, 29);
|
||||
this.button1.TabIndex = 4;
|
||||
this.button1.Text = "button1";
|
||||
this.button1.UseVisualStyleBackColor = true;
|
||||
this.button1.Click += new System.EventHandler(this.button1_Click);
|
||||
//
|
||||
// SetupForm
|
||||
//
|
||||
this.AcceptButton = this.btn_save;
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
||||
this.ClientSize = new System.Drawing.Size(663, 684);
|
||||
this.Controls.Add(this.button1);
|
||||
this.Controls.Add(this.btn_save);
|
||||
this.Controls.Add(this.prg_config);
|
||||
this.Name = "SetupForm";
|
||||
this.Text = "setup";
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SetupForm_FormClosed);
|
||||
this.Load += new System.EventHandler(this.SetupForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btn_save;
|
||||
private System.Windows.Forms.PropertyGrid prg_config;
|
||||
private System.Windows.Forms.Button button1;
|
||||
}
|
||||
}
|
||||
229
UdpPlugWebsocket/UI/setup.cs
Normal file
229
UdpPlugWebsocket/UI/setup.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
///<summary>
|
||||
///模块编号:20180730
|
||||
///模块名:本地配置模块
|
||||
///作用:生成本地的存储信息
|
||||
///作者:Miuser
|
||||
///编写日期:20180730
|
||||
///版本:1.0
|
||||
///</summary>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
//Common reference
|
||||
using System.Threading;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Xml.Serialization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
//mongo DB
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Bson;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
|
||||
namespace UserLogin
|
||||
{
|
||||
|
||||
public partial class SetupForm : Form
|
||||
{
|
||||
Config cfg;
|
||||
public SetupForm(ref Config config)
|
||||
{
|
||||
cfg = config;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void SetupForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
prg_config.SelectedObject = cfg;
|
||||
}
|
||||
|
||||
private void btn_save_Click(object sender, EventArgs e)
|
||||
{
|
||||
cfg.SavetoFile("config.xml");
|
||||
Application.Restart();
|
||||
|
||||
}
|
||||
|
||||
private void SetupForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void button1_Click(object sender, EventArgs e)
|
||||
{
|
||||
cfg.ShopList.Add("大岛店[01]");
|
||||
cfg.ShopList.Add("洞庭路店[02]");
|
||||
}
|
||||
}
|
||||
public class Config
|
||||
{
|
||||
[CategoryAttribute("1.MongoDB设置")]
|
||||
public String url { get; set; } //192.168.0.33
|
||||
[CategoryAttribute("1.MongoDB设置")]
|
||||
public String port { get; set; }
|
||||
[CategoryAttribute("1.MongoDB设置")]
|
||||
public String user { get; set; }
|
||||
|
||||
[CategoryAttribute("1.MongoDB设置")]
|
||||
|
||||
[BrowsableAttribute(false)]
|
||||
public String Epass { get; set; }
|
||||
|
||||
[CategoryAttribute("1.MongoDB设置")]
|
||||
[PasswordPropertyText(true)]
|
||||
[System.Xml.Serialization.XmlIgnore]
|
||||
public String pass
|
||||
{
|
||||
get
|
||||
{
|
||||
return Encryption.Decode(Epass);
|
||||
}
|
||||
set
|
||||
{
|
||||
Epass = Encryption.Encode(value);
|
||||
}
|
||||
}
|
||||
|
||||
[CategoryAttribute("1.MongoDB设置")]
|
||||
public String database { get; set; }
|
||||
|
||||
[CategoryAttribute("2.球机设定")]
|
||||
public int GolfPrivilegeTime { get; set; }
|
||||
[CategoryAttribute("2.球机设定")]
|
||||
public string ShopName { get; set; }
|
||||
[CategoryAttribute("2.球机设定")]
|
||||
public List<string> ShopList { get; set; }
|
||||
public int SavetoFile(String filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(Config));
|
||||
TextWriter writer = new StreamWriter(filename);
|
||||
serializer.Serialize(writer, this);
|
||||
writer.Close();
|
||||
}
|
||||
|
||||
catch (Exception ee)
|
||||
{
|
||||
MessageBox.Show(ee.StackTrace, ee.Message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
public static Config LoadfromFile(String filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
Config sptr;
|
||||
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(Config));
|
||||
TextReader reader = new StreamReader(filename);
|
||||
sptr = (Config)(serializer.Deserialize(reader));
|
||||
reader.Close();
|
||||
return sptr;
|
||||
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
MessageBox.Show(ee.StackTrace, ee.Message);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public class Encryption
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 作用:将字符串内容转化为16进制数据编码,其逆过程是Decode
|
||||
/// 参数说明:
|
||||
/// strEncode 需要转化的原始字符串
|
||||
/// 转换的过程是直接把字符转换成Unicode字符,比如数字"3"-->0033,汉字"我"-->U+6211
|
||||
/// 函数decode的过程是encode的逆过程.
|
||||
/// </summary>
|
||||
public static string Encode(string strEncode)
|
||||
{
|
||||
string strReturn = "";// 存储转换后的编码
|
||||
try
|
||||
{
|
||||
foreach (short shortx in strEncode.ToCharArray())
|
||||
{
|
||||
strReturn += shortx.ToString("X4");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return strReturn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作用:将16进制数据编码转化为字符串,是Encode的逆过程
|
||||
/// </summary>
|
||||
public static string Decode(string strDecode)
|
||||
{
|
||||
string sResult = "";
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < strDecode.Length / 4; i++)
|
||||
{
|
||||
sResult += (char)short.Parse(strDecode.Substring(i * 4, 4),
|
||||
global::System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return sResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将数字转换成16进制字符串,后两位加入随机字符,其可逆方法为DecodeForNum
|
||||
/// </summary>
|
||||
public static string EncodeForNum(int id)
|
||||
{
|
||||
//用户加上起始位置后的
|
||||
int startUserIndex = id;
|
||||
//转换成16进制
|
||||
string hexStr = Convert.ToString(startUserIndex, 16);
|
||||
|
||||
//后面两位加入随机数
|
||||
string randomchars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
string tmpstr = "";
|
||||
|
||||
//整除的后得到的数可能大于被除数
|
||||
tmpstr += randomchars[(id / randomchars.Length) > randomchars.Length ? randomchars.Length - 1 : (id / randomchars.Length)];
|
||||
|
||||
//余数不可能大于被除数
|
||||
tmpstr += randomchars[(id % randomchars.Length) > randomchars.Length ? randomchars.Length - 1 : (id % randomchars.Length)];
|
||||
|
||||
//返回拼接后的字符,转成大写
|
||||
string retStr = (hexStr + tmpstr).ToUpper();
|
||||
|
||||
return retStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密16进制字符串,此方法只适合后面两位有随机字符的
|
||||
/// </summary>
|
||||
public static int DecodeForNum(string strDecode)
|
||||
{
|
||||
if (strDecode.Length > 2)
|
||||
{
|
||||
strDecode = strDecode.Substring(0, strDecode.Length - 2);
|
||||
return Convert.ToInt32(strDecode, 16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
120
UdpPlugWebsocket/UI/setup.resx
Normal file
120
UdpPlugWebsocket/UI/setup.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
157
UdpPlugWebsocket/UdpPlugWebsocket.csproj
Normal file
157
UdpPlugWebsocket/UdpPlugWebsocket.csproj
Normal file
@@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{54CF701B-B076-4FC3-8A01-7434111A1C5B}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>UdpPlugWebsocket</RootNamespace>
|
||||
<AssemblyName>UdpPlugWebsocket</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="websocket-sharp">
|
||||
<HintPath>..\packages\WebSocketSharp-netstandard.1.0.1\lib\net45\websocket-sharp.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Browser.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Browser.Designer.cs">
|
||||
<DependentUpon>Browser.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Device\Device.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Device\Device.Designer.cs">
|
||||
<DependentUpon>Device.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Device\SocketConnection.cs" />
|
||||
<Compile Include="Device\SocketServer.cs" />
|
||||
<Compile Include="Form1.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Form1.Designer.cs">
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Message\ErrorForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Message\ErrorForm.designer.cs">
|
||||
<DependentUpon>ErrorForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Message\MessageForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Message\MessageForm.Designer.cs">
|
||||
<DependentUpon>MessageForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Panel\Node.cs" />
|
||||
<Compile Include="Panel\Panel.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Panel\Panel.Designer.cs">
|
||||
<DependentUpon>Panel.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Panel\Switch.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="setup.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="setup.designer.cs">
|
||||
<DependentUpon>setup.cs</DependentUpon>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="Browser.resx">
|
||||
<DependentUpon>Browser.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Device\Device.resx">
|
||||
<DependentUpon>Device.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Form1.resx">
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Message\ErrorForm.resx">
|
||||
<DependentUpon>ErrorForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Message\MessageForm.resx">
|
||||
<DependentUpon>MessageForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Panel\Panel.resx">
|
||||
<DependentUpon>Panel.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="setup.resx">
|
||||
<DependentUpon>setup.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="ClassDiagram1.cd" />
|
||||
<None Include="ClassDiagram2.cd" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<None Include="ReadMe.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
170
UdpPlugWebsocket/WebSocketServer/WebSocketForm.Designer.cs
generated
Normal file
170
UdpPlugWebsocket/WebSocketServer/WebSocketForm.Designer.cs
generated
Normal file
@@ -0,0 +1,170 @@
|
||||
namespace DoorControl
|
||||
{
|
||||
partial class WebSocketForm
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows 窗体设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.rtb_Server = new System.Windows.Forms.RichTextBox();
|
||||
this.btn_Send = new System.Windows.Forms.Button();
|
||||
this.txt_server = new System.Windows.Forms.TextBox();
|
||||
this.txt_msg_serversend = new System.Windows.Forms.TextBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.button1 = new System.Windows.Forms.Button();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.lis_sessions = new System.Windows.Forms.ListBox();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// rtb_Server
|
||||
//
|
||||
this.rtb_Server.Location = new System.Drawing.Point(377, 66);
|
||||
this.rtb_Server.Name = "rtb_Server";
|
||||
this.rtb_Server.Size = new System.Drawing.Size(415, 199);
|
||||
this.rtb_Server.TabIndex = 0;
|
||||
this.rtb_Server.Text = "";
|
||||
//
|
||||
// btn_Send
|
||||
//
|
||||
this.btn_Send.Location = new System.Drawing.Point(706, 23);
|
||||
this.btn_Send.Name = "btn_Send";
|
||||
this.btn_Send.Size = new System.Drawing.Size(70, 21);
|
||||
this.btn_Send.TabIndex = 1;
|
||||
this.btn_Send.Text = "发送";
|
||||
this.btn_Send.UseVisualStyleBackColor = true;
|
||||
this.btn_Send.Click += new System.EventHandler(this.btn_Send_Click);
|
||||
//
|
||||
// txt_server
|
||||
//
|
||||
this.txt_server.Location = new System.Drawing.Point(101, 27);
|
||||
this.txt_server.Name = "txt_server";
|
||||
this.txt_server.Size = new System.Drawing.Size(183, 21);
|
||||
this.txt_server.TabIndex = 2;
|
||||
this.txt_server.Text = "0.0.0.0:6666";
|
||||
//
|
||||
// txt_msg_serversend
|
||||
//
|
||||
this.txt_msg_serversend.Location = new System.Drawing.Point(477, 23);
|
||||
this.txt_msg_serversend.Name = "txt_msg_serversend";
|
||||
this.txt_msg_serversend.Size = new System.Drawing.Size(210, 21);
|
||||
this.txt_msg_serversend.TabIndex = 3;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(424, 27);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(47, 12);
|
||||
this.label2.TabIndex = 5;
|
||||
this.label2.Text = "Message";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(375, 51);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(23, 12);
|
||||
this.label3.TabIndex = 6;
|
||||
this.label3.Text = "Log";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.button1);
|
||||
this.groupBox1.Controls.Add(this.label1);
|
||||
this.groupBox1.Controls.Add(this.lis_sessions);
|
||||
this.groupBox1.Controls.Add(this.label3);
|
||||
this.groupBox1.Controls.Add(this.rtb_Server);
|
||||
this.groupBox1.Controls.Add(this.label2);
|
||||
this.groupBox1.Controls.Add(this.btn_Send);
|
||||
this.groupBox1.Controls.Add(this.txt_server);
|
||||
this.groupBox1.Controls.Add(this.txt_msg_serversend);
|
||||
this.groupBox1.Location = new System.Drawing.Point(46, 63);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(821, 367);
|
||||
this.groupBox1.TabIndex = 7;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Server";
|
||||
//
|
||||
// button1
|
||||
//
|
||||
this.button1.Location = new System.Drawing.Point(290, 26);
|
||||
this.button1.Name = "button1";
|
||||
this.button1.Size = new System.Drawing.Size(54, 22);
|
||||
this.button1.TabIndex = 9;
|
||||
this.button1.Text = "Start";
|
||||
this.button1.UseVisualStyleBackColor = true;
|
||||
this.button1.Click += new System.EventHandler(this.button1_Click_1);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(36, 30);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(59, 12);
|
||||
this.label1.TabIndex = 8;
|
||||
this.label1.Text = "Server IP";
|
||||
//
|
||||
// lis_sessions
|
||||
//
|
||||
this.lis_sessions.FormattingEnabled = true;
|
||||
this.lis_sessions.ItemHeight = 12;
|
||||
this.lis_sessions.Location = new System.Drawing.Point(38, 66);
|
||||
this.lis_sessions.Name = "lis_sessions";
|
||||
this.lis_sessions.Size = new System.Drawing.Size(304, 196);
|
||||
this.lis_sessions.TabIndex = 7;
|
||||
//
|
||||
// WebSocketForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1060, 693);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Name = "WebSocketForm";
|
||||
this.Text = "WebSocketServer";
|
||||
this.Load += new System.EventHandler(this.Form1_Load);
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.RichTextBox rtb_Server;
|
||||
private System.Windows.Forms.Button btn_Send;
|
||||
private System.Windows.Forms.TextBox txt_server;
|
||||
private System.Windows.Forms.TextBox txt_msg_serversend;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.ListBox lis_sessions;
|
||||
private System.Windows.Forms.Button button1;
|
||||
}
|
||||
}
|
||||
|
||||
162
UdpPlugWebsocket/WebSocketServer/WebSocketForm.cs
Normal file
162
UdpPlugWebsocket/WebSocketServer/WebSocketForm.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Management;
|
||||
using WebSocketSharp;
|
||||
using WebSocketSharp.Server;
|
||||
|
||||
namespace DoorControl
|
||||
{
|
||||
public partial class WebSocketForm : Form
|
||||
{
|
||||
WebSocketServer wssv;
|
||||
|
||||
|
||||
private delegate void DelegateStringFun(string log);//代理
|
||||
|
||||
public static WebSocketForm frm;
|
||||
public string text;
|
||||
public string textclient;
|
||||
|
||||
//自身的句柄
|
||||
public static void SendMessage(String msg)
|
||||
{
|
||||
frm.Log(msg);
|
||||
}
|
||||
|
||||
public static void ConnectionAccepted(String id)
|
||||
{
|
||||
frm.AddList(id);
|
||||
}
|
||||
|
||||
public static void ConnectionDismiss(String id)
|
||||
{
|
||||
frm.RemoveList(id);
|
||||
}
|
||||
public static String logtxt = "";
|
||||
|
||||
public WebSocketForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
frm = this;
|
||||
|
||||
|
||||
}
|
||||
public string Getlog()
|
||||
{
|
||||
string ret = logtxt;
|
||||
logtxt = "";
|
||||
return ret;
|
||||
}
|
||||
|
||||
public class MyEventArg : EventArgs
|
||||
{
|
||||
//传递主窗体的数据信息
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
private void Form1_Load(object sender, EventArgs e)
|
||||
{
|
||||
wssv = new WebSocketServer("ws://" +txt_server.Text);
|
||||
|
||||
}
|
||||
public class Laputa : WebSocketBehavior
|
||||
{
|
||||
protected override void OnOpen()
|
||||
{
|
||||
base.OnOpen();
|
||||
SendMessage("Connect from "+Context.Host + " was accepted");
|
||||
ConnectionAccepted(ID+"|"+ Context.Host.ToString());
|
||||
|
||||
}
|
||||
protected override void OnClose(CloseEventArgs e)
|
||||
{
|
||||
SendMessage("Connect from " + Context.Host + " was lost");
|
||||
ConnectionDismiss(ID + "|" + Context.Host.ToString());
|
||||
base.OnClose(e);
|
||||
|
||||
}
|
||||
protected override void OnMessage(MessageEventArgs e)
|
||||
{
|
||||
|
||||
string s_data = e.Data;
|
||||
Logger log=new Logger();
|
||||
SendMessage("Server Received: "+e.Data);
|
||||
Console.Write(e.Data);
|
||||
//Loopback
|
||||
//Send(e.Data);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Log(string log)
|
||||
{
|
||||
if (this.rtb_Server.InvokeRequired)
|
||||
{
|
||||
DelegateStringFun d = new DelegateStringFun(Log);
|
||||
this.Invoke(d, new object[] { log });
|
||||
}
|
||||
else
|
||||
{
|
||||
text= text + log.Replace("\0","") + "\n";
|
||||
rtb_Server.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddList(string id)
|
||||
{
|
||||
if (this.rtb_Server.InvokeRequired)
|
||||
{
|
||||
DelegateStringFun d = new DelegateStringFun(AddList);
|
||||
this.Invoke(d, new object[] { id });
|
||||
}
|
||||
else
|
||||
{
|
||||
lis_sessions.Items.Add(id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveList(string id)
|
||||
{
|
||||
if (this.rtb_Server.InvokeRequired)
|
||||
{
|
||||
DelegateStringFun d = new DelegateStringFun(RemoveList);
|
||||
this.Invoke(d, new object[] { id });
|
||||
}
|
||||
else
|
||||
{
|
||||
lis_sessions.Items.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void btn_Send_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
string s_mixid = lis_sessions.SelectedItem.ToString();
|
||||
string s_id = s_mixid.Substring(0, s_mixid.IndexOf("|"));
|
||||
wssv.WebSocketServices["/"].Sessions.SendToAsync(txt_msg_serversend.Text, s_id, null);
|
||||
}catch
|
||||
{
|
||||
MessageBox.Show("请先选择session");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void button1_Click_1(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
120
UdpPlugWebsocket/WebSocketServer/WebSocketForm.resx
Normal file
120
UdpPlugWebsocket/WebSocketServer/WebSocketForm.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
97
UdpPlugWebsocket/WebSocketServer/WebSocketServer.csproj
Normal file
97
UdpPlugWebsocket/WebSocketServer/WebSocketServer.csproj
Normal file
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{D5A6D030-FDDE-462F-94E5-A78F312107FD}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>WebSocketServer</RootNamespace>
|
||||
<AssemblyName>WebSocketServer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="websocket-sharp, Version=1.0.1.0, Culture=neutral, PublicKeyToken=5660b08a1845a91e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WebSocketSharp-netstandard.1.0.1\lib\net45\websocket-sharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="WebSocketForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="WebSocketForm.Designer.cs">
|
||||
<DependentUpon>WebSocketForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<EmbeddedResource Include="WebSocketForm.resx">
|
||||
<DependentUpon>WebSocketForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
209
UdpPlugWebsocket/setup.cs
Normal file
209
UdpPlugWebsocket/setup.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
///<summary>
|
||||
///模块编号:20180730
|
||||
///模块名:本地配置模块
|
||||
///作用:生成本地的存储信息
|
||||
///作者:Miuser
|
||||
///编写日期:20180730
|
||||
///版本:1.0
|
||||
///</summary>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
//Common reference
|
||||
using System.Threading;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Xml.Serialization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
//mongo DB
|
||||
|
||||
using System.Security.Cryptography;
|
||||
|
||||
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
|
||||
public partial class SetupForm : Form
|
||||
{
|
||||
public static Config cfg;
|
||||
public SetupForm(ref Config config)
|
||||
{
|
||||
cfg = config;
|
||||
InitializeComponent();
|
||||
}
|
||||
public SetupForm()
|
||||
{
|
||||
cfg = Config.LoadfromFile("config.xml");
|
||||
InitializeComponent();
|
||||
}
|
||||
private void SetupForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
prg_config.SelectedObject = cfg;
|
||||
}
|
||||
|
||||
private void btn_save_Click(object sender, EventArgs e)
|
||||
{
|
||||
cfg.SavetoFile("config.xml");
|
||||
Application.Restart();
|
||||
}
|
||||
|
||||
private void SetupForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
public class Config
|
||||
{
|
||||
[CategoryAttribute("1.Websocket Port")]
|
||||
public String BrowserPort { get; set; }
|
||||
|
||||
|
||||
[CategoryAttribute("2.UDP Port")]
|
||||
public int UDPPort { get; set; }
|
||||
[CategoryAttribute("2.UDP TTL (ms)")]
|
||||
public int UDPTTL { get; set; }
|
||||
|
||||
[CategoryAttribute("3.NODE TTL (ms)")]
|
||||
public int NODETTL { get; set; }
|
||||
|
||||
|
||||
//记录日志
|
||||
//[CategoryAttribute("4.Enable File Log")]
|
||||
//public bool EnableFileLog { get; set; }
|
||||
|
||||
//屏幕显示
|
||||
[CategoryAttribute("4.Enable Screen Log")]
|
||||
public bool EnableScreenLog { get; set; }
|
||||
|
||||
public int SavetoFile(String filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(Config));
|
||||
TextWriter writer = new StreamWriter(filename);
|
||||
serializer.Serialize(writer, this);
|
||||
writer.Close();
|
||||
}
|
||||
|
||||
catch (Exception ee)
|
||||
{
|
||||
MessageBox.Show(ee.StackTrace, ee.Message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
public static Config LoadfromFile(String filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
Config sptr;
|
||||
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(Config));
|
||||
TextReader reader = new StreamReader(filename);
|
||||
sptr = (Config)(serializer.Deserialize(reader));
|
||||
reader.Close();
|
||||
return sptr;
|
||||
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
MessageBox.Show(ee.StackTrace, ee.Message);
|
||||
return new Config();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public class Encryption
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 作用:将字符串内容转化为16进制数据编码,其逆过程是Decode
|
||||
/// 参数说明:
|
||||
/// strEncode 需要转化的原始字符串
|
||||
/// 转换的过程是直接把字符转换成Unicode字符,比如数字"3"-->0033,汉字"我"-->U+6211
|
||||
/// 函数decode的过程是encode的逆过程.
|
||||
/// </summary>
|
||||
public static string Encode(string strEncode)
|
||||
{
|
||||
string strReturn = "";// 存储转换后的编码
|
||||
try
|
||||
{
|
||||
foreach (short shortx in strEncode.ToCharArray())
|
||||
{
|
||||
strReturn += shortx.ToString("X4");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return strReturn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作用:将16进制数据编码转化为字符串,是Encode的逆过程
|
||||
/// </summary>
|
||||
public static string Decode(string strDecode)
|
||||
{
|
||||
string sResult = "";
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < strDecode.Length / 4; i++)
|
||||
{
|
||||
sResult += (char)short.Parse(strDecode.Substring(i * 4, 4),
|
||||
global::System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return sResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将数字转换成16进制字符串,后两位加入随机字符,其可逆方法为DecodeForNum
|
||||
/// </summary>
|
||||
public static string EncodeForNum(int id)
|
||||
{
|
||||
//用户加上起始位置后的
|
||||
int startUserIndex = id;
|
||||
//转换成16进制
|
||||
string hexStr = Convert.ToString(startUserIndex, 16);
|
||||
|
||||
//后面两位加入随机数
|
||||
string randomchars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
string tmpstr = "";
|
||||
|
||||
//整除的后得到的数可能大于被除数
|
||||
tmpstr += randomchars[(id / randomchars.Length) > randomchars.Length ? randomchars.Length - 1 : (id / randomchars.Length)];
|
||||
|
||||
//余数不可能大于被除数
|
||||
tmpstr += randomchars[(id % randomchars.Length) > randomchars.Length ? randomchars.Length - 1 : (id % randomchars.Length)];
|
||||
|
||||
//返回拼接后的字符,转成大写
|
||||
string retStr = (hexStr + tmpstr).ToUpper();
|
||||
|
||||
return retStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密16进制字符串,此方法只适合后面两位有随机字符的
|
||||
/// </summary>
|
||||
public static int DecodeForNum(string strDecode)
|
||||
{
|
||||
if (strDecode.Length > 2)
|
||||
{
|
||||
strDecode = strDecode.Substring(0, strDecode.Length - 2);
|
||||
return Convert.ToInt32(strDecode, 16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
75
UdpPlugWebsocket/setup.designer.cs
generated
Normal file
75
UdpPlugWebsocket/setup.designer.cs
generated
Normal file
@@ -0,0 +1,75 @@
|
||||
namespace UdpPlugWebsocket
|
||||
{
|
||||
partial class SetupForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btn_save = new System.Windows.Forms.Button();
|
||||
this.prg_config = new System.Windows.Forms.PropertyGrid();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btn_save
|
||||
//
|
||||
this.btn_save.Location = new System.Drawing.Point(443, 641);
|
||||
this.btn_save.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.btn_save.Name = "btn_save";
|
||||
this.btn_save.Size = new System.Drawing.Size(178, 30);
|
||||
this.btn_save.TabIndex = 3;
|
||||
this.btn_save.Text = "保存并重启";
|
||||
this.btn_save.UseVisualStyleBackColor = true;
|
||||
this.btn_save.Click += new System.EventHandler(this.btn_save_Click);
|
||||
//
|
||||
// prg_config
|
||||
//
|
||||
this.prg_config.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.prg_config.Location = new System.Drawing.Point(0, 0);
|
||||
this.prg_config.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.prg_config.Name = "prg_config";
|
||||
this.prg_config.Size = new System.Drawing.Size(663, 684);
|
||||
this.prg_config.TabIndex = 2;
|
||||
//
|
||||
// SetupForm
|
||||
//
|
||||
this.AcceptButton = this.btn_save;
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
||||
this.ClientSize = new System.Drawing.Size(663, 684);
|
||||
this.Controls.Add(this.btn_save);
|
||||
this.Controls.Add(this.prg_config);
|
||||
this.Name = "SetupForm";
|
||||
this.Text = "setup";
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SetupForm_FormClosed);
|
||||
this.Load += new System.EventHandler(this.SetupForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btn_save;
|
||||
private System.Windows.Forms.PropertyGrid prg_config;
|
||||
}
|
||||
}
|
||||
120
UdpPlugWebsocket/setup.resx
Normal file
120
UdpPlugWebsocket/setup.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
BIN
bin_UPWS/UdpPlugWebsocket.exe
Normal file
BIN
bin_UPWS/UdpPlugWebsocket.exe
Normal file
Binary file not shown.
6
bin_UPWS/UdpPlugWebsocket.exe.config
Normal file
6
bin_UPWS/UdpPlugWebsocket.exe.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
BIN
bin_UPWS/UdpPlugWebsocket.vshost.exe
Normal file
BIN
bin_UPWS/UdpPlugWebsocket.vshost.exe
Normal file
Binary file not shown.
6
bin_UPWS/UdpPlugWebsocket.vshost.exe.config
Normal file
6
bin_UPWS/UdpPlugWebsocket.vshost.exe.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
11
bin_UPWS/UdpPlugWebsocket.vshost.exe.manifest
Normal file
11
bin_UPWS/UdpPlugWebsocket.vshost.exe.manifest
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
37
bin_UPWS/WebSocketClient.html
Normal file
37
bin_UPWS/WebSocketClient.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
var socket;
|
||||
if ("WebSocket" in window) {
|
||||
var ws = new WebSocket("ws://127.0.0.1:9000");
|
||||
socket = ws;
|
||||
ws.onopen = function() {
|
||||
console.log('连接成功');
|
||||
};
|
||||
ws.onmessage = function(evt) {
|
||||
var received_msg = evt.data;
|
||||
document.getElementById("showMes").value+=evt.data+"\n";
|
||||
};
|
||||
ws.onclose = function() {
|
||||
alert("断开了连接");
|
||||
};
|
||||
} else {
|
||||
alert("浏览器不支持WebSocket");
|
||||
}
|
||||
function login(){
|
||||
var message=document.getElementById("name").value+":"+document.getElementById("mes").value;
|
||||
socket.send(message);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<textarea rows="3" cols="30" id="showMes" style="width:300px;height:500px;"></textarea>
|
||||
<br/>
|
||||
<label>名称</label>
|
||||
<input type="text" id="name"/>
|
||||
<br/>
|
||||
<label>消息</label>
|
||||
<input type="text" id="mes"/>
|
||||
<button onclick="login();">发送</button>
|
||||
</body>
|
||||
</html>
|
||||
BIN
bin_UPWS/client.exe
Normal file
BIN
bin_UPWS/client.exe
Normal file
Binary file not shown.
9
bin_UPWS/config.xml
Normal file
9
bin_UPWS/config.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<BrowserPort>9000</BrowserPort>
|
||||
<UDPPort>7101</UDPPort>
|
||||
<UDPTTL>30000</UDPTTL>
|
||||
<NODETTL>20000</NODETTL>
|
||||
<EnableFileLog>true</EnableFileLog>
|
||||
<EnableScreenLog>true</EnableScreenLog>
|
||||
</Config>
|
||||
3
bin_UPWS/main/JustGage.js
Normal file
3
bin_UPWS/main/JustGage.js
Normal file
File diff suppressed because one or more lines are too long
2
bin_UPWS/main/jquery-1.8.3.min.js
vendored
Normal file
2
bin_UPWS/main/jquery-1.8.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
bin_UPWS/main/reconnecting-websocket.min.js
vendored
Normal file
1
bin_UPWS/main/reconnecting-websocket.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(a,b){"function"==typeof define&&define.amd?define([],b):"undefined"!=typeof module&&module.exports?module.exports=b():a.ReconnectingWebSocket=b()}(this,function(){function a(b,c,d){function l(a,b){var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,!1,!1,b),c}var e={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3};d||(d={});for(var f in e)this[f]="undefined"!=typeof d[f]?d[f]:e[f];this.url=b,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var h,g=this,i=!1,j=!1,k=document.createElement("div");k.addEventListener("open",function(a){g.onopen(a)}),k.addEventListener("close",function(a){g.onclose(a)}),k.addEventListener("connecting",function(a){g.onconnecting(a)}),k.addEventListener("message",function(a){g.onmessage(a)}),k.addEventListener("error",function(a){g.onerror(a)}),this.addEventListener=k.addEventListener.bind(k),this.removeEventListener=k.removeEventListener.bind(k),this.dispatchEvent=k.dispatchEvent.bind(k),this.open=function(b){h=new WebSocket(g.url,c||[]),b||k.dispatchEvent(l("connecting")),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",g.url);var d=h,e=setTimeout(function(){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",g.url),j=!0,d.close(),j=!1},g.timeoutInterval);h.onopen=function(){clearTimeout(e),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onopen",g.url),g.protocol=h.protocol,g.readyState=WebSocket.OPEN,g.reconnectAttempts=0;var d=l("open");d.isReconnect=b,b=!1,k.dispatchEvent(d)},h.onclose=function(c){if(clearTimeout(e),h=null,i)g.readyState=WebSocket.CLOSED,k.dispatchEvent(l("close"));else{g.readyState=WebSocket.CONNECTING;var d=l("connecting");d.code=c.code,d.reason=c.reason,d.wasClean=c.wasClean,k.dispatchEvent(d),b||j||((g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onclose",g.url),k.dispatchEvent(l("close")));var e=g.reconnectInterval*Math.pow(g.reconnectDecay,g.reconnectAttempts);setTimeout(function(){g.reconnectAttempts++,g.open(!0)},e>g.maxReconnectInterval?g.maxReconnectInterval:e)}},h.onmessage=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",g.url,b.data);var c=l("message");c.data=b.data,k.dispatchEvent(c)},h.onerror=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onerror",g.url,b),k.dispatchEvent(l("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(b){if(h)return(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","send",g.url,b),h.send(b);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(a,b){"undefined"==typeof a&&(a=1e3),i=!0,h&&h.close(a,b)},this.refresh=function(){h&&h.close()}}return a.prototype.onopen=function(){},a.prototype.onclose=function(){},a.prototype.onconnecting=function(){},a.prototype.onmessage=function(){},a.prototype.onerror=function(){},a.debugAll=!1,a.CONNECTING=WebSocket.CONNECTING,a.OPEN=WebSocket.OPEN,a.CLOSING=WebSocket.CLOSING,a.CLOSED=WebSocket.CLOSED,a});
|
||||
BIN
bin_UPWS/udp.dll
Normal file
BIN
bin_UPWS/udp.dll
Normal file
Binary file not shown.
BIN
bin_UPWS/websocket-sharp.dll
Normal file
BIN
bin_UPWS/websocket-sharp.dll
Normal file
Binary file not shown.
10326
bin_UPWS/websocket-sharp.xml
Normal file
10326
bin_UPWS/websocket-sharp.xml
Normal file
File diff suppressed because it is too large
Load Diff
BIN
document/clienttest.png
Normal file
BIN
document/clienttest.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
111
document/function.md
Normal file
111
document/function.md
Normal file
@@ -0,0 +1,111 @@
|
||||
## 工作原理 ##
|
||||
本项目仿照硬件设计思想,基于模块化原理开发,分为UDP连接池、Websocket连接池、交换面板三个大的模块。各个模块相互独立,除消息通讯外无模块间耦合。每个模块的功能部分和UI部分彼此亦基本独立。UDP和Websocket两个模块采用.net内置的Action对象与交换面板进行异步消息通讯。
|
||||
|
||||
**Endpoint是外部连接的唯一索引。**
|
||||
|
||||
**Endpoint字符串的格式为:"XXX.XXX.XXX.XXX:XXXX" 前四组三位数为IP地址,最后一组四位数为远程端口号**
|
||||
|
||||
UDP连接池是一个UDP连接管理模块,默认开放7101端口,供外部连接接入。每个成功连接的设备或模拟程序会被分配一个SocketConnection,SocketConnction通过Tag属性进行索引(Tag的值默认为Endpoint)并添加到一个列表里,该列表可以通过 GetConnectionList()获得,也可以使用GetTheConnection(Func<SocketConnection, bool> predicate)函数通过LINQ语句进行指定连接的查询。
|
||||
|
||||
|
||||
|
||||
以下为UDP连接池对外暴露的函数接口
|
||||
|
||||
|
||||
/// 开始服务,监听客户端
|
||||
public void StartServer()
|
||||
///按照IP地址和端口发送字符串
|
||||
public void Send(string EndpointString, byte[] bytes)
|
||||
///开始异步监听端口
|
||||
public void Listening()
|
||||
/// 关闭指定客户端连接
|
||||
public void CloseConnection(SocketConnection theConnection)
|
||||
/// 添加客户端连接
|
||||
public void AddConnection(SocketConnection theConnection)
|
||||
/// 通过条件获取客户端连接列表
|
||||
public IEnumerable<SocketConnection> GetConnectionList(Func<SocketConnection, bool> predicate)
|
||||
/// 获取所有客户端连接列表
|
||||
public IEnumerable<SocketConnection> GetConnectionList()
|
||||
/// 寻找特定条件的客户端连接
|
||||
public SocketConnection GetTheConnection(Func<SocketConnection, bool> predicate)
|
||||
/// 获取客户端连接数
|
||||
public int GetConnectionCount()
|
||||
|
||||
以下为UDP连接池对外暴露的事件接口
|
||||
|
||||
/// 服务启动后执行
|
||||
public Action<SocketServer> HandleServerStarted { get; set; }
|
||||
/// 当新客户端连接后执行
|
||||
public Action<SocketServer, SocketConnection> HandleNewClientConnected { get; set; }
|
||||
/// 客户端连接接受新的消息后调用
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; }
|
||||
/// 客户端连接发送消息后回调
|
||||
public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }
|
||||
/// 客户端连接关闭后回调
|
||||
public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }
|
||||
/// 异常处理程序
|
||||
public Action<Exception> HandleException { get; set; }
|
||||
|
||||
Websocket连接池是一个websocket管理模块,默认开放9000端口,供外部连接接入。每个成功联机的APP页面会分配一个唯一的session,Websocket对象维护了一个Sessions列表,该列表可以通过Where表达式,通过LINQ语句筛选。
|
||||
|
||||
以下为Websocket连接池对外暴露的函数接口
|
||||
|
||||
/// 发送字节
|
||||
public void Send(string EndpointString,byte[] bytes)
|
||||
|
||||
以下为Websocket连接池对外暴露的事件接口
|
||||
|
||||
/// 当新客户端连接后执行
|
||||
public Action<WebSocketSharp.Net.WebSockets.WebSocketContext> HandleNewWebSocketClientConnected { get; set; }
|
||||
/// 客户端连接接受新的消息后调用
|
||||
public Action<byte[], WebSocketSharp.Net.WebSockets.WebSocketContext> HandleWebSocketRecMsg { get; set; }
|
||||
/// 客户端连接发送消息后回调
|
||||
public Action<byte[], WebSocketSharp.Net.WebSockets.WebSocketContext> HandleWebSocketSendMsg { get; set; }
|
||||
/// 客户端连接关闭后回调
|
||||
public Action<WebSocketSharp.Net.WebSockets.WebSocketContext> HandleWebSocketClientClose { get; set; }
|
||||
|
||||
交换面板(Switch)是一个消息转发器,他接收UDP与Websocket传入的数据包,并根据数据包中ID部分对信息进行分组转发,既收到信息后,向ID相同的全部在线端口转发收到的原始消息。MM是标识设备控制权限的,供上层应用使用,服务端不做处理。
|
||||
|
||||
对于每一个ID,Switch会生成一个结点(Node),该节点存储了含有相同ID的Websocket和UDP连接信息 1)TTL(剩余生存时间)2 Endpoint(客户连接端口),每个结点自带生命计时器,靠上层程序定期执行Reactive()函数保活。
|
||||
|
||||
private void Init_Forms()
|
||||
{
|
||||
try
|
||||
{
|
||||
...
|
||||
|
||||
//连接模块与系统终端窗口
|
||||
Device.Instance.HandleMessage += new Action<string>(MessageForm.Log);
|
||||
Device.Instance.HandleError += new Action<string>(ErrorForm.Log);
|
||||
|
||||
Browser.Instance.HandleMessage += new Action<string>(MessageForm.Log);
|
||||
Browser.Instance.HandleError += new Action<string>(ErrorForm.Log);
|
||||
//连接Pannel数据输入端 Device->Panel
|
||||
Device.Instance.server.HandleRecMsg += new Action<byte[], Miuser.NUDP.Sockets.SocketConnection, Miuser.NUDP.Sockets.SocketServer>((bytes, conn, server) =>
|
||||
{
|
||||
Panel.Instance.sw.SendFromUDP(bytes, conn.Tag.ToString());
|
||||
});
|
||||
//连接Pannel数据输入端 Browser->Panel
|
||||
Browser.Instance.HandleWebSocketRecMsg += new Action<byte[], WebSocketSharp.Net.WebSockets.WebSocketContext>((bytes, context) =>
|
||||
{
|
||||
Panel.Instance.sw.SendFromWebSocket(bytes, context.UserEndPoint.ToString());
|
||||
});
|
||||
//连接Pannel数据输出端 Panel->Device
|
||||
Panel.Instance.sw.HandleUDPSendMsg += new Action<byte[], string>((bytes, endpointString) =>
|
||||
{
|
||||
Device.Instance.server.Send(endpointString, bytes);
|
||||
});
|
||||
//连接Panel数据输出端 Panel->Browser
|
||||
Panel.Instance.sw.HandleWebSocketSendMsg += new Action<byte[], string>((bytes, endpointString)=>
|
||||
{
|
||||
Browser.Instance.Send(endpointString, bytes);
|
||||
});
|
||||
|
||||
...
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.StackTrace,"系统模块初始化错误");
|
||||
|
||||
}
|
||||
}
|
||||
BIN
document/packageintro.png
Normal file
BIN
document/packageintro.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
BIN
document/preview.png
Normal file
BIN
document/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
BIN
document/webtest.png
Normal file
BIN
document/webtest.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
26
websocket-sharp/AssemblyInfo.cs
Normal file
26
websocket-sharp/AssemblyInfo.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("websocket-sharp")]
|
||||
[assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("websocket-sharp.dll")]
|
||||
[assembly: AssemblyCopyright("sta.blockhead")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.2.*")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
||||
47
websocket-sharp/ByteOrder.cs
Normal file
47
websocket-sharp/ByteOrder.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
#region License
|
||||
/*
|
||||
* ByteOrder.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012-2015 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the byte order.
|
||||
/// </summary>
|
||||
public enum ByteOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies Little-endian.
|
||||
/// </summary>
|
||||
Little,
|
||||
/// <summary>
|
||||
/// Specifies Big-endian.
|
||||
/// </summary>
|
||||
Big
|
||||
}
|
||||
}
|
||||
142
websocket-sharp/CloseEventArgs.cs
Normal file
142
websocket-sharp/CloseEventArgs.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
#region License
|
||||
/*
|
||||
* CloseEventArgs.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012-2016 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the event data for the <see cref="WebSocket.OnClose"/> event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// That event occurs when the WebSocket connection has been closed.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If you would like to get the reason for the close, you should access
|
||||
/// the <see cref="Code"/> or <see cref="Reason"/> property.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class CloseEventArgs : EventArgs
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private bool _clean;
|
||||
private PayloadData _payloadData;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Constructors
|
||||
|
||||
internal CloseEventArgs ()
|
||||
{
|
||||
_payloadData = PayloadData.Empty;
|
||||
}
|
||||
|
||||
internal CloseEventArgs (ushort code)
|
||||
: this (code, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal CloseEventArgs (CloseStatusCode code)
|
||||
: this ((ushort) code, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal CloseEventArgs (PayloadData payloadData)
|
||||
{
|
||||
_payloadData = payloadData;
|
||||
}
|
||||
|
||||
internal CloseEventArgs (ushort code, string reason)
|
||||
{
|
||||
_payloadData = new PayloadData (code, reason);
|
||||
}
|
||||
|
||||
internal CloseEventArgs (CloseStatusCode code, string reason)
|
||||
: this ((ushort) code, reason)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Properties
|
||||
|
||||
internal PayloadData PayloadData {
|
||||
get {
|
||||
return _payloadData;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status code for the close.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ushort"/> that represents the status code for the close if any.
|
||||
/// </value>
|
||||
public ushort Code {
|
||||
get {
|
||||
return _payloadData.Code;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reason for the close.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string"/> that represents the reason for the close if any.
|
||||
/// </value>
|
||||
public string Reason {
|
||||
get {
|
||||
return _payloadData.Reason ?? String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the connection has been closed cleanly.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the connection has been closed cleanly; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool WasClean {
|
||||
get {
|
||||
return _clean;
|
||||
}
|
||||
|
||||
internal set {
|
||||
_clean = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
120
websocket-sharp/CloseStatusCode.cs
Normal file
120
websocket-sharp/CloseStatusCode.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
#region License
|
||||
/*
|
||||
* CloseStatusCode.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012-2016 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the status code for the WebSocket connection close.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The values of this enumeration are defined in
|
||||
/// <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
|
||||
/// Section 7.4</see> of RFC 6455.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// "Reserved value" cannot be sent as a status code in
|
||||
/// closing handshake by an endpoint.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public enum CloseStatusCode : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1000. Indicates normal close.
|
||||
/// </summary>
|
||||
Normal = 1000,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1001. Indicates that an endpoint is
|
||||
/// going away.
|
||||
/// </summary>
|
||||
Away = 1001,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1002. Indicates that an endpoint is
|
||||
/// terminating the connection due to a protocol error.
|
||||
/// </summary>
|
||||
ProtocolError = 1002,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1003. Indicates that an endpoint is
|
||||
/// terminating the connection because it has received a type of
|
||||
/// data that it cannot accept.
|
||||
/// </summary>
|
||||
UnsupportedData = 1003,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1004. Still undefined. A Reserved value.
|
||||
/// </summary>
|
||||
Undefined = 1004,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1005. Indicates that no status code was
|
||||
/// actually present. A Reserved value.
|
||||
/// </summary>
|
||||
NoStatus = 1005,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1006. Indicates that the connection was
|
||||
/// closed abnormally. A Reserved value.
|
||||
/// </summary>
|
||||
Abnormal = 1006,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1007. Indicates that an endpoint is
|
||||
/// terminating the connection because it has received a message that
|
||||
/// contains data that is not consistent with the type of the message.
|
||||
/// </summary>
|
||||
InvalidData = 1007,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1008. Indicates that an endpoint is
|
||||
/// terminating the connection because it has received a message that
|
||||
/// violates its policy.
|
||||
/// </summary>
|
||||
PolicyViolation = 1008,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1009. Indicates that an endpoint is
|
||||
/// terminating the connection because it has received a message that
|
||||
/// is too big to process.
|
||||
/// </summary>
|
||||
TooBig = 1009,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1010. Indicates that a client is
|
||||
/// terminating the connection because it has expected the server to
|
||||
/// negotiate one or more extension, but the server did not return
|
||||
/// them in the handshake response.
|
||||
/// </summary>
|
||||
MandatoryExtension = 1010,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1011. Indicates that a server is
|
||||
/// terminating the connection because it has encountered an unexpected
|
||||
/// condition that prevented it from fulfilling the request.
|
||||
/// </summary>
|
||||
ServerError = 1011,
|
||||
/// <summary>
|
||||
/// Equivalent to close status 1015. Indicates that the connection was
|
||||
/// closed due to a failure to perform a TLS handshake. A Reserved value.
|
||||
/// </summary>
|
||||
TlsHandshakeFailure = 1015
|
||||
}
|
||||
}
|
||||
52
websocket-sharp/CompressionMethod.cs
Normal file
52
websocket-sharp/CompressionMethod.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
#region License
|
||||
/*
|
||||
* CompressionMethod.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2013-2017 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the method for compression.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The methods are defined in
|
||||
/// <see href="https://tools.ietf.org/html/rfc7692">
|
||||
/// Compression Extensions for WebSocket</see>.
|
||||
/// </remarks>
|
||||
public enum CompressionMethod : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies no compression.
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Specifies DEFLATE.
|
||||
/// </summary>
|
||||
Deflate
|
||||
}
|
||||
}
|
||||
109
websocket-sharp/ErrorEventArgs.cs
Normal file
109
websocket-sharp/ErrorEventArgs.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
#region License
|
||||
/*
|
||||
* ErrorEventArgs.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012-2016 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#region Contributors
|
||||
/*
|
||||
* Contributors:
|
||||
* - Frank Razenberg <frank@zzattack.org>
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the event data for the <see cref="WebSocket.OnError"/> event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// That event occurs when the <see cref="WebSocket"/> gets an error.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If you would like to get the error message, you should access
|
||||
/// the <see cref="ErrorEventArgs.Message"/> property.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// And if the error is due to an exception, you can get it by accessing
|
||||
/// the <see cref="ErrorEventArgs.Exception"/> property.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class ErrorEventArgs : EventArgs
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private Exception _exception;
|
||||
private string _message;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Constructors
|
||||
|
||||
internal ErrorEventArgs (string message)
|
||||
: this (message, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal ErrorEventArgs (string message, Exception exception)
|
||||
{
|
||||
_message = message;
|
||||
_exception = exception;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exception that caused the error.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// An <see cref="System.Exception"/> instance that represents the cause of
|
||||
/// the error if it is due to an exception; otherwise, <see langword="null"/>.
|
||||
/// </value>
|
||||
public Exception Exception {
|
||||
get {
|
||||
return _exception;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error message.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string"/> that represents the error message.
|
||||
/// </value>
|
||||
public string Message {
|
||||
get {
|
||||
return _message;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2032
websocket-sharp/Ext.cs
Normal file
2032
websocket-sharp/Ext.cs
Normal file
File diff suppressed because it is too large
Load Diff
51
websocket-sharp/Fin.cs
Normal file
51
websocket-sharp/Fin.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
#region License
|
||||
/*
|
||||
* Fin.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012-2015 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether a WebSocket frame is the final frame of a message.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The values of this enumeration are defined in
|
||||
/// <see href="http://tools.ietf.org/html/rfc6455#section-5.2">Section 5.2</see> of RFC 6455.
|
||||
/// </remarks>
|
||||
internal enum Fin : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Equivalent to numeric value 0. Indicates more frames of a message follow.
|
||||
/// </summary>
|
||||
More = 0x0,
|
||||
/// <summary>
|
||||
/// Equivalent to numeric value 1. Indicates the final frame of a message.
|
||||
/// </summary>
|
||||
Final = 0x1
|
||||
}
|
||||
}
|
||||
208
websocket-sharp/HttpBase.cs
Normal file
208
websocket-sharp/HttpBase.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
#region License
|
||||
/*
|
||||
* HttpBase.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012-2014 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using WebSocketSharp.Net;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
internal abstract class HttpBase
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private NameValueCollection _headers;
|
||||
private const int _headersMaxLength = 8192;
|
||||
private Version _version;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Fields
|
||||
|
||||
internal byte[] EntityBodyData;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected const string CrLf = "\r\n";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Constructors
|
||||
|
||||
protected HttpBase (Version version, NameValueCollection headers)
|
||||
{
|
||||
_version = version;
|
||||
_headers = headers;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public string EntityBody {
|
||||
get {
|
||||
if (EntityBodyData == null || EntityBodyData.LongLength == 0)
|
||||
return String.Empty;
|
||||
|
||||
Encoding enc = null;
|
||||
|
||||
var contentType = _headers["Content-Type"];
|
||||
if (contentType != null && contentType.Length > 0)
|
||||
enc = HttpUtility.GetEncoding (contentType);
|
||||
|
||||
return (enc ?? Encoding.UTF8).GetString (EntityBodyData);
|
||||
}
|
||||
}
|
||||
|
||||
public NameValueCollection Headers {
|
||||
get {
|
||||
return _headers;
|
||||
}
|
||||
}
|
||||
|
||||
public Version ProtocolVersion {
|
||||
get {
|
||||
return _version;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private static byte[] readEntityBody (Stream stream, string length)
|
||||
{
|
||||
long len;
|
||||
if (!Int64.TryParse (length, out len))
|
||||
throw new ArgumentException ("Cannot be parsed.", "length");
|
||||
|
||||
if (len < 0)
|
||||
throw new ArgumentOutOfRangeException ("length", "Less than zero.");
|
||||
|
||||
return len > 1024
|
||||
? stream.ReadBytes (len, 1024)
|
||||
: len > 0
|
||||
? stream.ReadBytes ((int) len)
|
||||
: null;
|
||||
}
|
||||
|
||||
private static string[] readHeaders (Stream stream, int maxLength)
|
||||
{
|
||||
var buff = new List<byte> ();
|
||||
var cnt = 0;
|
||||
Action<int> add = i => {
|
||||
if (i == -1)
|
||||
throw new EndOfStreamException ("The header cannot be read from the data source.");
|
||||
|
||||
buff.Add ((byte) i);
|
||||
cnt++;
|
||||
};
|
||||
|
||||
var read = false;
|
||||
while (cnt < maxLength) {
|
||||
if (stream.ReadByte ().EqualsWith ('\r', add) &&
|
||||
stream.ReadByte ().EqualsWith ('\n', add) &&
|
||||
stream.ReadByte ().EqualsWith ('\r', add) &&
|
||||
stream.ReadByte ().EqualsWith ('\n', add)) {
|
||||
read = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!read)
|
||||
throw new WebSocketException ("The length of header part is greater than the max length.");
|
||||
|
||||
return Encoding.UTF8.GetString (buff.ToArray ())
|
||||
.Replace (CrLf + " ", " ")
|
||||
.Replace (CrLf + "\t", " ")
|
||||
.Split (new[] { CrLf }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected static T Read<T> (Stream stream, Func<string[], T> parser, int millisecondsTimeout)
|
||||
where T : HttpBase
|
||||
{
|
||||
var timeout = false;
|
||||
var timer = new Timer (
|
||||
state => {
|
||||
timeout = true;
|
||||
stream.Close ();
|
||||
},
|
||||
null,
|
||||
millisecondsTimeout,
|
||||
-1);
|
||||
|
||||
T http = null;
|
||||
Exception exception = null;
|
||||
try {
|
||||
http = parser (readHeaders (stream, _headersMaxLength));
|
||||
var contentLen = http.Headers["Content-Length"];
|
||||
if (contentLen != null && contentLen.Length > 0)
|
||||
http.EntityBodyData = readEntityBody (stream, contentLen);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
exception = ex;
|
||||
}
|
||||
finally {
|
||||
timer.Change (-1, -1);
|
||||
timer.Dispose ();
|
||||
}
|
||||
|
||||
var msg = timeout
|
||||
? "A timeout has occurred while reading an HTTP request/response."
|
||||
: exception != null
|
||||
? "An exception has occurred while reading an HTTP request/response."
|
||||
: null;
|
||||
|
||||
if (msg != null)
|
||||
throw new WebSocketException (msg, exception);
|
||||
|
||||
return http;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public byte[] ToByteArray ()
|
||||
{
|
||||
return Encoding.UTF8.GetBytes (ToString ());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
217
websocket-sharp/HttpRequest.cs
Normal file
217
websocket-sharp/HttpRequest.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
#region License
|
||||
/*
|
||||
* HttpRequest.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012-2015 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
#region Contributors
|
||||
/*
|
||||
* Contributors:
|
||||
* - David Burhans
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using WebSocketSharp.Net;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
internal class HttpRequest : HttpBase
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private CookieCollection _cookies;
|
||||
private string _method;
|
||||
private string _uri;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Constructors
|
||||
|
||||
private HttpRequest (string method, string uri, Version version, NameValueCollection headers)
|
||||
: base (version, headers)
|
||||
{
|
||||
_method = method;
|
||||
_uri = uri;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Constructors
|
||||
|
||||
internal HttpRequest (string method, string uri)
|
||||
: this (method, uri, HttpVersion.Version11, new NameValueCollection ())
|
||||
{
|
||||
Headers["User-Agent"] = "websocket-sharp/1.0";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public AuthenticationResponse AuthenticationResponse {
|
||||
get {
|
||||
var res = Headers["Authorization"];
|
||||
return res != null && res.Length > 0
|
||||
? AuthenticationResponse.Parse (res)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
public CookieCollection Cookies {
|
||||
get {
|
||||
if (_cookies == null)
|
||||
_cookies = Headers.GetCookies (false);
|
||||
|
||||
return _cookies;
|
||||
}
|
||||
}
|
||||
|
||||
public string HttpMethod {
|
||||
get {
|
||||
return _method;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWebSocketRequest {
|
||||
get {
|
||||
return _method == "GET"
|
||||
&& ProtocolVersion > HttpVersion.Version10
|
||||
&& Headers.Upgrades ("websocket");
|
||||
}
|
||||
}
|
||||
|
||||
public string RequestUri {
|
||||
get {
|
||||
return _uri;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal static HttpRequest CreateConnectRequest (Uri uri)
|
||||
{
|
||||
var host = uri.DnsSafeHost;
|
||||
var port = uri.Port;
|
||||
var authority = String.Format ("{0}:{1}", host, port);
|
||||
var req = new HttpRequest ("CONNECT", authority);
|
||||
req.Headers["Host"] = port == 80 ? host : authority;
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
internal static HttpRequest CreateWebSocketRequest (Uri uri)
|
||||
{
|
||||
var req = new HttpRequest ("GET", uri.PathAndQuery);
|
||||
var headers = req.Headers;
|
||||
|
||||
// Only includes a port number in the Host header value if it's non-default.
|
||||
// See: https://tools.ietf.org/html/rfc6455#page-17
|
||||
var port = uri.Port;
|
||||
var schm = uri.Scheme;
|
||||
headers["Host"] = (port == 80 && schm == "ws") || (port == 443 && schm == "wss")
|
||||
? uri.DnsSafeHost
|
||||
: uri.Authority;
|
||||
|
||||
headers["Upgrade"] = "websocket";
|
||||
headers["Connection"] = "Upgrade";
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
internal HttpResponse GetResponse (Stream stream, int millisecondsTimeout)
|
||||
{
|
||||
var buff = ToByteArray ();
|
||||
stream.Write (buff, 0, buff.Length);
|
||||
|
||||
return Read<HttpResponse> (stream, HttpResponse.Parse, millisecondsTimeout);
|
||||
}
|
||||
|
||||
internal static HttpRequest Parse (string[] headerParts)
|
||||
{
|
||||
var requestLine = headerParts[0].Split (new[] { ' ' }, 3);
|
||||
if (requestLine.Length != 3)
|
||||
throw new ArgumentException ("Invalid request line: " + headerParts[0]);
|
||||
|
||||
var headers = new WebHeaderCollection ();
|
||||
for (int i = 1; i < headerParts.Length; i++)
|
||||
headers.InternalSet (headerParts[i], false);
|
||||
|
||||
return new HttpRequest (
|
||||
requestLine[0], requestLine[1], new Version (requestLine[2].Substring (5)), headers);
|
||||
}
|
||||
|
||||
internal static HttpRequest Read (Stream stream, int millisecondsTimeout)
|
||||
{
|
||||
return Read<HttpRequest> (stream, Parse, millisecondsTimeout);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void SetCookies (CookieCollection cookies)
|
||||
{
|
||||
if (cookies == null || cookies.Count == 0)
|
||||
return;
|
||||
|
||||
var buff = new StringBuilder (64);
|
||||
foreach (var cookie in cookies.Sorted)
|
||||
if (!cookie.Expired)
|
||||
buff.AppendFormat ("{0}; ", cookie.ToString ());
|
||||
|
||||
var len = buff.Length;
|
||||
if (len > 2) {
|
||||
buff.Length = len - 2;
|
||||
Headers["Cookie"] = buff.ToString ();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
var output = new StringBuilder (64);
|
||||
output.AppendFormat ("{0} {1} HTTP/{2}{3}", _method, _uri, ProtocolVersion, CrLf);
|
||||
|
||||
var headers = Headers;
|
||||
foreach (var key in headers.AllKeys)
|
||||
output.AppendFormat ("{0}: {1}{2}", key, headers[key], CrLf);
|
||||
|
||||
output.Append (CrLf);
|
||||
|
||||
var entity = EntityBody;
|
||||
if (entity.Length > 0)
|
||||
output.Append (entity);
|
||||
|
||||
return output.ToString ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
209
websocket-sharp/HttpResponse.cs
Normal file
209
websocket-sharp/HttpResponse.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
#region License
|
||||
/*
|
||||
* HttpResponse.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012-2014 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using WebSocketSharp.Net;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
internal class HttpResponse : HttpBase
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private string _code;
|
||||
private string _reason;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Constructors
|
||||
|
||||
private HttpResponse (string code, string reason, Version version, NameValueCollection headers)
|
||||
: base (version, headers)
|
||||
{
|
||||
_code = code;
|
||||
_reason = reason;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Constructors
|
||||
|
||||
internal HttpResponse (HttpStatusCode code)
|
||||
: this (code, code.GetDescription ())
|
||||
{
|
||||
}
|
||||
|
||||
internal HttpResponse (HttpStatusCode code, string reason)
|
||||
: this (((int) code).ToString (), reason, HttpVersion.Version11, new NameValueCollection ())
|
||||
{
|
||||
Headers["Server"] = "websocket-sharp/1.0";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public CookieCollection Cookies {
|
||||
get {
|
||||
return Headers.GetCookies (true);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasConnectionClose {
|
||||
get {
|
||||
var comparison = StringComparison.OrdinalIgnoreCase;
|
||||
return Headers.Contains ("Connection", "close", comparison);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsProxyAuthenticationRequired {
|
||||
get {
|
||||
return _code == "407";
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRedirect {
|
||||
get {
|
||||
return _code == "301" || _code == "302";
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsUnauthorized {
|
||||
get {
|
||||
return _code == "401";
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWebSocketResponse {
|
||||
get {
|
||||
return ProtocolVersion > HttpVersion.Version10
|
||||
&& _code == "101"
|
||||
&& Headers.Upgrades ("websocket");
|
||||
}
|
||||
}
|
||||
|
||||
public string Reason {
|
||||
get {
|
||||
return _reason;
|
||||
}
|
||||
}
|
||||
|
||||
public string StatusCode {
|
||||
get {
|
||||
return _code;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal static HttpResponse CreateCloseResponse (HttpStatusCode code)
|
||||
{
|
||||
var res = new HttpResponse (code);
|
||||
res.Headers["Connection"] = "close";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
internal static HttpResponse CreateUnauthorizedResponse (string challenge)
|
||||
{
|
||||
var res = new HttpResponse (HttpStatusCode.Unauthorized);
|
||||
res.Headers["WWW-Authenticate"] = challenge;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
internal static HttpResponse CreateWebSocketResponse ()
|
||||
{
|
||||
var res = new HttpResponse (HttpStatusCode.SwitchingProtocols);
|
||||
|
||||
var headers = res.Headers;
|
||||
headers["Upgrade"] = "websocket";
|
||||
headers["Connection"] = "Upgrade";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
internal static HttpResponse Parse (string[] headerParts)
|
||||
{
|
||||
var statusLine = headerParts[0].Split (new[] { ' ' }, 3);
|
||||
if (statusLine.Length != 3)
|
||||
throw new ArgumentException ("Invalid status line: " + headerParts[0]);
|
||||
|
||||
var headers = new WebHeaderCollection ();
|
||||
for (int i = 1; i < headerParts.Length; i++)
|
||||
headers.InternalSet (headerParts[i], true);
|
||||
|
||||
return new HttpResponse (
|
||||
statusLine[1], statusLine[2], new Version (statusLine[0].Substring (5)), headers);
|
||||
}
|
||||
|
||||
internal static HttpResponse Read (Stream stream, int millisecondsTimeout)
|
||||
{
|
||||
return Read<HttpResponse> (stream, Parse, millisecondsTimeout);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void SetCookies (CookieCollection cookies)
|
||||
{
|
||||
if (cookies == null || cookies.Count == 0)
|
||||
return;
|
||||
|
||||
var headers = Headers;
|
||||
foreach (var cookie in cookies.Sorted)
|
||||
headers.Add ("Set-Cookie", cookie.ToResponseString ());
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
var output = new StringBuilder (64);
|
||||
output.AppendFormat ("HTTP/{0} {1} {2}{3}", ProtocolVersion, _code, _reason, CrLf);
|
||||
|
||||
var headers = Headers;
|
||||
foreach (var key in headers.AllKeys)
|
||||
output.AppendFormat ("{0}: {1}{2}", key, headers[key], CrLf);
|
||||
|
||||
output.Append (CrLf);
|
||||
|
||||
var entity = EntityBody;
|
||||
if (entity.Length > 0)
|
||||
output.Append (entity);
|
||||
|
||||
return output.ToString ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user