目录
一、需求
在使用之前,引入Fleck插件,下面案例将采用winfrom作为服务器,html为客户端
需要注意的是,本案例经过测试有一个问题,就是客户端如果连接上服务器后,如果长时间不通讯,那么连接会自动断开,这里其实可以写一个类似TCP协议的心跳机制来解决这个问题。
二、WebSocket 封装
web_socket代码
- using Fleck;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace WebSocket
- {
- public class Web_Socket
- {
- //客户端url以及其对应的Socket对象字典
- IDictionary<string, IWebSocketConnection> dic_Sockets = new Dictionary<string, IWebSocketConnection>();
- //创建一个 websocket ,0.0.0.0 为监听所有的的地址
- WebSocketServer server = new WebSocketServer("ws://0.0.0.0:30000");
-
- //打开连接委托
- public delegate void _OnOpen(string ip);
- public event _OnOpen OnOpen;
- //关闭连接委托
- public delegate void _OnClose(string ip);
- public event _OnClose OnClose;
- //当收到消息
- public delegate void _OnMessage(string ip, string msg);
- public event _OnMessage OnMessage;
-
- ///
- /// 初始化
- ///
- private void Init()
- {
- //出错后进行重启
- server.RestartAfterListenError = true;
-
- //开始监听
- server.Start(socket =>
- {
- //连接建立事件
- socket.OnOpen = () =>
- {
- //获取客户端网页的url
- string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
- dic_Sockets.Add(clientUrl, socket);
- if (OnOpen != null) OnOpen(clientUrl);
- Console.WriteLine(DateTime.Now.ToString() + " | 服务器:和客户端网页:" + clientUrl + " 建立WebSock连接!");
- };
-
- //连接关闭事件
- socket.OnClose = () =>
- {
- string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
- //如果存在这个客户端,那么对这个socket进行移除
- if (dic_Sockets.ContainsKey(clientUrl))
- {
- dic_Sockets.Remove(clientUrl);
- if (OnClose != null) OnClose(clientUrl);
- }
- Console.WriteLine(DateTime.Now.ToString() + " | 服务器:和客户端网页:" + clientUrl + " 断开WebSock连接!");
- };
-
- //接受客户端网页消息事件
- socket.OnMessage = message =>
- {
- string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
- Receive(clientUrl, message);
- if (OnMessage != null) OnMessage(clientUrl, message);
- };
- });
- }
-
- ///
- /// 向客户端发送消息
- ///
- /// 客户端实例
- /// 消息内容
- public void Send(string clientUrl, string message)
- {
- IWebSocketConnection webSocketConnection = GetUserSocketInstance(clientUrl);
- if (webSocketConnection != null)
- {
- if (webSocketConnection.IsAvailable)
- {
- webSocketConnection.Send(message);
- }
- }
- }
-
- ///
- /// 接收消息
- ///
- ///
- ///
- private void Receive(string clientUrl, string message)
- {
- Console.WriteLine(DateTime.Now.ToString() + " | 服务器:【收到】来客户端网页:" + clientUrl + "的信息:\n" + message);
- }
-
- ///
- /// 获取用户实例
- ///
- /// 用户的地址
- public IWebSocketConnection GetUserSocketInstance(string clientUrl)
- {
- if (dic_Sockets.ContainsKey(clientUrl))
- return dic_Sockets[clientUrl];
- else
- return null;
- }
-
- ///
- /// 关闭某一个用户的连接
- ///
- ///
- public void CloseUserConnect(string clientUrl)
- {
- IWebSocketConnection webSocketConnection = GetUserSocketInstance(clientUrl);
- if (webSocketConnection != null)
- webSocketConnection.Close();
- }
-
- ///
- /// 关闭与客户端的所有的连接
- ///
- public void CloseAllConnect()
- {
- foreach (var item in dic_Sockets.Values)
- {
- if (item != null)
- {
- item.Close();
- }
- }
- }
-
- public Web_Socket()
- {
- Init();
- }
- }
- }
三、前端部分
winform 界面

Form1代码:
- using Fleck;
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
-
- namespace WebSocket
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
-
- private Web_Socket webSocket = new Web_Socket();
-
- private void Form1_Load(object sender, EventArgs e)
- {
- webSocket.OnOpen += this.OnOpen;
- webSocket.OnClose += this.OnClose;
- webSocket.OnMessage += this.OnMessage;
-
- Init();
- }
-
- private void Form1_FormClosing(object sender, FormClosingEventArgs e)
- {
- webSocket.CloseAllConnect();
- }
-
- private void Init()
- {
-
- }
-
- //当有客户端连接
- private void OnOpen(string clientUrl)
- {
- this.Invoke(new MethodInvoker(delegate
- {
- ComboBox_IPAddres.Items.Add(clientUrl);
- if (ComboBox_IPAddres.Items.Count > 0)
- ComboBox_IPAddres.SelectedIndex = 0;
- ListBox_IPList.Items.Insert(ListBox_IPList.Items.Count, clientUrl);
- }));
- AddLogToListView("用户加入", string.Empty, string.Format("IP:{0} 加入了连接", clientUrl), true);
- }
-
- //当客户端关闭
- private void OnClose(string clientUrl)
- {
- this.Invoke(new MethodInvoker(delegate
- {
- ComboBox_IPAddres.Items.Remove(clientUrl);
- ListBox_IPList.Items.Remove(clientUrl);
- }));
- AddLogToListView("用户退出", string.Empty, string.Format("IP:{0} 关闭了连接", clientUrl), true);
- }
-
- //当收到客户端消息
- private void OnMessage(string clientUrl, string message)
- {
- AddLogToListView("服务器接收", clientUrl, message);
- }
-
- ///
- /// 添加日志到日志列表
- ///
- ///
- ///
- private void AddLogToListView(string title, string clientUrl, string message, bool rest = false)
- {
- this.Invoke(new MethodInvoker(delegate
- {
- int len = ListBox_MessageList.Items.Count;
- if (!rest)
- ListBox_MessageList.Items.Insert(len, string.Format("[{0}] IP:{1} 内容:{2}", title, clientUrl, message));
- else
- ListBox_MessageList.Items.Insert(len, string.Format("[{0}] {1}", title, message));
- }));
- }
-
- ///
- /// 发送按钮点击事件
- ///
- ///
- ///
- private void Button_Send_Click(object sender, EventArgs e)
- {
- string clientUrl = ComboBox_IPAddres.Text;
- string content = TextBox_Message.Text;
- if (string.IsNullOrEmpty(content))
- {
- MessageBox.Show("发送内容为空");
- return;
- }
- if (string.IsNullOrEmpty(clientUrl))
- {
- MessageBox.Show("请选择一个IP地址");
- return;
- }
- webSocket.Send(clientUrl, content);
- TextBox_Message.Text = string.Empty;
- AddLogToListView("服务器发送", clientUrl, content);
- }
- }
- }
四、网页端
html:
- HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
- <html>
- <head>
- <title>websocket clienttitle>
- <script type="text/javascript">
- var start = function () {
- var inc = document.getElementById('incomming');
- var wsImpl = window.WebSocket || window.MozWebSocket;
- var form = document.getElementById('sendForm');
- var input = document.getElementById('sendText');
-
- inc.innerHTML += "连接服务器..
"; -
- // 创建一个新的websocket并连接
- window.ws = new wsImpl('ws://localhost:30000/');
-
- // 当数据来自服务器时,将调用此方法
- ws.onmessage = function (evt) {
- inc.innerHTML += ("[来自服务器的消息] " + evt.data + '
'); - console.log("[来自服务器的消息] " + evt.data);
- };
-
- // 当建立连接时,将调用此方法
- ws.onopen = function () {
- inc.innerHTML += '已建立连接..
'; - };
-
- // 当连接关闭时,将调用此方法
- ws.onclose = function () {
- inc.innerHTML += '连接已关闭..
'; - }
-
- form.addEventListener('submit', function (e) {
- e.preventDefault();
- var val = input.value;
- ws.send(val);
- input.value = "";
- });
- }
- window.onload = start;
- script>
- head>
- <body>
- <form id="sendForm">
- <span>输入内容按回车发送消息span> <br/>
- <input id="sendText" placeholder="Text to send" />
- form>
- <pre id="incomming">pre>
- body>
- html>
经过测试,发送,接收消息正常
代码:
- using Newtonsoft.Json;
- using System.IO;
- using System.Net;
- using System.Text;
-
- namespace HTTP
- {
- public class RestClient
- {
- ///
- /// Get请求
- ///
- /// 请求url
- ///
- public static string Get(string url)
- {
- HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
- if (req == null || req.GetResponse() == null)
- return string.Empty;
-
- HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
- if (resp == null)
- return string.Empty;
-
- using (Stream stream = resp.GetResponseStream())
- {
- //获取内容
- using (StreamReader reader = new StreamReader(stream))
- {
- return reader.ReadToEnd();
- }
- }
- }
-
-
- ///
- /// Post请求
- ///
- ///
- ///
- ///
- public static string Post(string url, object postData)
- {
- HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
- if (req == null)
- return string.Empty;
-
- req.Method = "POST";
- req.ContentType = "application/json";
- req.Timeout = 15000;
-
- byte[] data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(postData));
- //注意:无需手动指定长度 (否则可能会报流未处理完就关闭的异常,因为ContentLength时候会比真实post数据长度大)
- //req.ContentLength = data.Length;
- using (Stream reqStream = req.GetRequestStream())
- {
- reqStream.Write(data, 0, data.Length);
- }
-
- HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
- if (resp == null)
- return string.Empty;
-
- using (Stream stream = resp.GetResponseStream())
- {
- using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
- {
- return reader.ReadToEnd();
- }
- }
- }
-
- }
- }
上面的Post请求在有些接口可能没有效果,可以使用下面的方法,其中第一个方法是无参数的Post请求,第二个方法只要将所需的Key和Value添加进字典就行了
- ///
- /// 指定Post地址使用Get 方式获取全部字符串
- ///
- /// 请求后台地址
- ///
- public static string Post(string url)
- {
- string result = "";
- HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
- req.Method = "POST";
- HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
- Stream stream = resp.GetResponseStream();
- //获取内容
- using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
- {
- result = reader.ReadToEnd();
- }
- return result;
- }
-
-
- ///
- /// 指定Post地址使用Get 方式获取全部字符串
- ///
- /// 请求后台地址
- ///
- public static string Post(string url, Dictionary<string, string> dic)
- {
- string result = "";
- HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
- req.Method = "POST";
- req.ContentType = "application/x-www-form-urlencoded";
- #region 添加Post 参数
- StringBuilder builder = new StringBuilder();
- int i = 0;
- foreach (var item in dic)
- {
- if (i > 0)
- builder.Append("&");
- builder.AppendFormat("{0}={1}", item.Key, item.Value);
- i++;
- }
- byte[] data = Encoding.UTF8.GetBytes(builder.ToString());
- req.ContentLength = data.Length;
- using (Stream reqStream = req.GetRequestStream())
- {
- reqStream.Write(data, 0, data.Length);
- reqStream.Close();
- }
- #endregion
- HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
- Stream stream = resp.GetResponseStream();
- //获取响应内容
- using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
- {
- result = reader.ReadToEnd();
- }
- return result;
- }
1.无返回值方式
代码:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
-
- namespace MyTask
- {
- class Program
- {
- static void Main(string[] args)
- {
- List
taskList = new List(); - taskList.Add(Task.Factory.StartNew(() =>
- {
- Thread.Sleep(1000);
- Console.WriteLine("1秒执行结束");
- }));
- taskList.Add(Task.Factory.StartNew(() =>
- {
- Thread.Sleep(800);
- Console.WriteLine("o.8秒执行结束");
- }));
-
- Console.WriteLine("执行中");
-
- TaskFactory taskFactory = new TaskFactory();
- taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), tArray =>
- {
- Thread.Sleep(200);
- Console.WriteLine("等待这些完成后执行");
- }));
-
- Console.ReadKey();
- }
- }
- }
运行:

这里由于作了延时处理,执行顺序不一致
假设任务中出现异常:
代码:
- taskList.Add(Task.Factory.StartNew(() =>
- {
- try
- {
- int a = int.Parse("");
- }
- catch (Exception ex)
- {
- Console.WriteLine("=========异常:" + ex.Message);
- }
- Console.WriteLine("=========第二种方式");
- }));
运行:
![]()
2.有返回值方式
代码:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
-
- namespace MyTask
- {
- class Program
- {
- static void Main(string[] args)
- {
- List
int>> taskList1 = new Listint>>(); - taskList1.Add(Task<int>.Factory.StartNew(() =>
- {
- int num = 3 * 5;
- Console.WriteLine("有返回值的任务队列 1");
- return num;
- }
- ));
- taskList1.Add(Task<int>.Factory.StartNew(() =>
- {
- int num = 3 * 7;
- Console.WriteLine("有返回值的任务队列 2");
- return num;
- }
- ));
- new TaskFactory().ContinueWhenAll(taskList1.ToArray(), tArray =>
- {
- Console.WriteLine("有返回值的任务队列执行完毕");
- foreach (Task<int> item in taskList1)
- {
- Console.WriteLine("执行结果:" + item.Result);
- }
- });
-
-
- Console.ReadKey();
- }
- }
- }
运行:

第一种:用线程
-
- private void Form1_Load(object sender, EventArgs e){
- timer = new System.Timers.Timer();
- timer.Interval = 3000;
- timer.AutoReset = false;
- timer.Enabled = true;
- timer.Elapsed += new System.Timers.ElapsedEventHandler(GetCurDateTime);
- }
-
- private void GetCurDateTime(object sender, System.Timers.ElapsedEventArgs e)
- {
- Label_Log.Text = string.Empty;
- }
第二种:用winform 自带的组件
- private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
-
- private void Form1_Load(object sender, EventArgs e){
- timer.Interval = 3000;
- timer.Tick += GetCurDateTime;
- timer.Enabled = true;
- }
-
- private void GetCurDateTime(object sender, EventArgs e)
- {
- Label_Log.Text = string.Empty;
- }
需要注意的是,两个对象中的字段必须是属性,带有get,set,否则无法识别,返回的就是false
代码
- ///
- /// 比较--两个类型一样的实体类对象的值
- ///
- ///
- ///
返回true表示两个对象的数据相同,返回false表示不相同 - private bool CompareType<T>(T oneT, T twoT)
- {
- bool result = true;//两个类型作比较时使用,如果有不一样的就false
- Type typeOne = oneT.GetType();
- Type typeTwo = twoT.GetType();
- //如果两个T类型不一样 就不作比较
- if (!typeOne.Equals(typeTwo)) { return false; }
- PropertyInfo[] pisOne = typeOne.GetProperties(); //获取所有公共属性(Public)
- PropertyInfo[] pisTwo = typeTwo.GetProperties();
- //如果长度为0返回false
- if (pisOne.Length <= 0 || pisTwo.Length <= 0)
- {
- return false;
- }
- //如果长度不一样,返回false
- if (!(pisOne.Length.Equals(pisTwo.Length))) { return false; }
- //遍历两个T类型,遍历属性,并作比较
- for (int i = 0; i < pisOne.Length; i++)
- {
- //获取属性名
- string oneName = pisOne[i].Name;
- string twoName = pisTwo[i].Name;
- //获取属性的值
- object oneValue = pisOne[i].GetValue(oneT, null);
- object twoValue = pisTwo[i].GetValue(twoT, null);
- //比较,只比较值类型
- if ((pisOne[i].PropertyType.IsValueType || pisOne[i].PropertyType.Name.StartsWith("String")) && (pisTwo[i].PropertyType.IsValueType || pisTwo[i].PropertyType.Name.StartsWith("String")))
- {
- if (oneName.Equals(twoName))
- {
- if (oneValue == null)
- {
- if (twoValue != null)
- {
- result = false;
- break; //如果有不一样的就退出循环
- }
- }
- else if (oneValue != null)
- {
- if (twoValue != null)
- {
- if (!oneValue.Equals(twoValue))
- {
- result = false;
- break; //如果有不一样的就退出循环
- }
- }
- else if (twoValue == null)
- {
- result = false;
- break; //如果有不一样的就退出循环
- }
- }
- }
- else
- {
- result = false;
- break;
- }
- }
- else
- {
- //如果对象中的属性是实体类对象,递归遍历比较
- bool b = CompareType(oneValue, twoValue);
- if (!b) { result = b; break; }
- }
- }
- return result;
- }
-
-
-
- //调用
- private void btnOrder_Click(object sender, EventArgs e)
- {
-
- //实体类比较
- UserVo userVoOne = new UserVo();
- UserVo userVoTwo = new UserVo();
-
- userVoOne.UserID = 1;
- //userVoOne.UserAccount = "a";
-
- userVoTwo.UserID = 1;
-
- bool flag = CompareType(userVoOne, userVoTwo);
- if (flag)
- {
- MessageBox.Show("两个类数据相同");
- }
- else
- {
- MessageBox.Show("两个类数据不相同");
- }
- }
界面:

代码:
- using Microsoft.Win32;
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
-
- namespace 开机启动
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
-
- //获得应用程序路径
- private string StrAssName = string.Empty;
- //获得应用程序名
- private string ShortFileName = string.Empty;
-
- private void Form1_Load(object sender, EventArgs e)
- {
-
- }
-
- //添加到开机启动
- public void AddPowerBoot()
- {
- try
- {
- if(string.IsNullOrEmpty(ShortFileName) || string.IsNullOrEmpty(StrAssName))
- {
- MessageBox.Show("输入框不能为空");
- return;
- }
-
- //此方法把启动项加载到注册表中
- //获得应用程序路径
- //string StrAssName = Application.StartupPath + @"\" + Application.ProductName + @".exe";
- //获得应用程序名
- //string ShortFileName = Application.ProductName;
- //路径:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run
- RegistryKey rgkRun = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
- if (rgkRun == null)
- {
- rgkRun = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
- }
- rgkRun.SetValue(ShortFileName, StrAssName);
- MessageBox.Show("添加到注册表成功");
- }
- catch (Exception ex)
- {
- MessageBox.Show("执行错误:" + ex.Message);
- }
- }
-
- //移除开机启动
- public void RemovePowerBoot()
- {
- try
- {
- if (string.IsNullOrEmpty(ShortFileName) || string.IsNullOrEmpty(StrAssName))
- {
- MessageBox.Show("输入框不能为空");
- return;
- }
-
- //此删除注册表中启动项
- //获得应用程序名
- //string ShortFileName = Application.ProductName;
- RegistryKey rgkRun = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
- if (rgkRun == null)
- {
- rgkRun = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
- }
- rgkRun.DeleteValue(ShortFileName, false);
- MessageBox.Show("移除注册表成功");
- }
- catch (Exception ex)
- {
- MessageBox.Show("执行错误:" + ex.Message);
- }
- }
-
- //设置开机启动
- private void Button_SetPowerBoot_Click(object sender, EventArgs e)
- {
- AddPowerBoot();
- }
-
- //移除开机启动
- private void Button_RemovePowerBoot_Click(object sender, EventArgs e)
- {
- RemovePowerBoot();
- }
-
- //选择要操作的程序
- private void Button_GetModuleFileName_Click(object sender, EventArgs e)
- {
- //创建对象
- OpenFileDialog ofg = new OpenFileDialog();
- //设置默认打开路径(绝对路径)
- ofg.InitialDirectory = "C:\\Users\\Administrator\\Desktop";
- //设置打开标题、后缀
- ofg.Title = "请选择程序的exe文件";
- ofg.Filter = "exe文件|*.exe";
- string path = string.Empty;
- if (ofg.ShowDialog() == DialogResult.OK)
- {
- //得到打开的文件路径(包括文件名)
- path = ofg.FileName.ToString();
- Console.WriteLine("打开文件路径是:" + path);
-
- TextBox_GetModuleFileName.Text = path;
- StrAssName = path;
-
- string[] arr = path.Split('\\');
- ShortFileName = arr[arr.Length - 1];
- Label_ProgramName.Text = "应用程序名:" + ShortFileName;
- }
- else if (ofg.ShowDialog() == DialogResult.Cancel)
- {
- MessageBox.Show("未选择打开文件!");
- }
- }
- }
- }
程序一定要用管理员身份运行,否则会报错
end