当前位置:   article > 正文

C# WebSocket(Fleck) 客户端:html Winfrom_c# websocket客户端

c# websocket客户端

================ 有bug,不推荐使用 ================

一、简介

WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

Websocket 用法和 TCP 协议差不多,在这里我用 C# 写服务器端, html 和 winform 作为客户端。

二、服务端

1.新建项目

新建一个控制台项目

在 NuGet 引入  Fleck 插件

2.WebSocketHelper

新建 WebSocketHelper.cs

代码

  1. using Fleck;
  2. namespace WebSocket
  3. {
  4. internal class WebSocketHelper
  5. {
  6. //客户端url以及其对应的Socket对象字典
  7. IDictionary<string, IWebSocketConnection> dic_Sockets = new Dictionary<string, IWebSocketConnection>();
  8. //创建一个 websocket ,0.0.0.0 为监听所有的的地址
  9. WebSocketServer server = new WebSocketServer("ws://0.0.0.0:30000");
  10. //打开连接委托
  11. public delegate void _OnOpen(string ip);
  12. public event _OnOpen OnOpen;
  13. //关闭连接委托
  14. public delegate void _OnClose(string ip);
  15. public event _OnClose OnClose;
  16. //当收到消息
  17. public delegate void _OnMessage(string ip, string msg);
  18. public event _OnMessage OnMessage;
  19. /// <summary>
  20. /// 初始化
  21. /// </summary>
  22. private void Init()
  23. {
  24. //出错后进行重启
  25. server.RestartAfterListenError = true;
  26. //开始监听
  27. server.Start(socket =>
  28. {
  29. //连接建立事件
  30. socket.OnOpen = () =>
  31. {
  32. //获取客户端网页的url
  33. string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
  34. dic_Sockets.Add(clientUrl, socket);
  35. if (OnOpen != null) OnOpen(clientUrl);
  36. Console.WriteLine(DateTime.Now.ToString() + " | 服务器:和客户端:" + clientUrl + " 建立WebSock连接!");
  37. };
  38. //连接关闭事件
  39. socket.OnClose = () =>
  40. {
  41. string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
  42. //如果存在这个客户端,那么对这个socket进行移除
  43. if (dic_Sockets.ContainsKey(clientUrl))
  44. {
  45. dic_Sockets.Remove(clientUrl);
  46. if (OnClose != null) OnClose(clientUrl);
  47. }
  48. Console.WriteLine(DateTime.Now.ToString() + " | 服务器:和客户端:" + clientUrl + " 断开WebSock连接!");
  49. };
  50. //接受客户端网页消息事件
  51. socket.OnMessage = message =>
  52. {
  53. string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
  54. Receive(clientUrl, message);
  55. if (OnMessage != null)
  56. OnMessage(clientUrl, message);
  57. };
  58. });
  59. }
  60. /// <summary>
  61. /// 向客户端发送消息
  62. /// </summary>
  63. /// <param name="webSocketConnection">客户端实例</param>
  64. /// <param name="message">消息内容</param>
  65. public void Send(string clientUrl, string message)
  66. {
  67. IWebSocketConnection webSocketConnection = GetUserSocketInstance(clientUrl);
  68. if (webSocketConnection != null)
  69. {
  70. if (webSocketConnection.IsAvailable)
  71. {
  72. webSocketConnection.Send(message);
  73. }
  74. }
  75. }
  76. /// <summary>
  77. /// 接收消息
  78. /// </summary>
  79. /// <param name="clientUrl"></param>
  80. /// <param name="message"></param>
  81. private void Receive(string clientUrl, string message)
  82. {
  83. Console.WriteLine(DateTime.Now.ToString() + " | 服务器:【收到】来客户端:" + clientUrl + "的信息:\n" + message);
  84. }
  85. /// <summary>
  86. /// 获取用户实例
  87. /// </summary>
  88. /// <param name="clientUrl">用户的地址</param>
  89. public IWebSocketConnection GetUserSocketInstance(string clientUrl)
  90. {
  91. if (dic_Sockets.ContainsKey(clientUrl))
  92. return dic_Sockets[clientUrl];
  93. else
  94. return null;
  95. }
  96. /// <summary>
  97. /// 关闭某一个用户的连接
  98. /// </summary>
  99. /// <param name="clientUrl"></param>
  100. public void CloseUserConnect(string clientUrl)
  101. {
  102. IWebSocketConnection webSocketConnection = GetUserSocketInstance(clientUrl);
  103. if (webSocketConnection != null)
  104. webSocketConnection.Close();
  105. }
  106. /// <summary>
  107. /// 关闭与客户端的所有的连接
  108. /// </summary>
  109. public void CloseAllConnect()
  110. {
  111. foreach (var item in dic_Sockets.Values)
  112. {
  113. if (item != null)
  114. {
  115. item.Close();
  116. }
  117. }
  118. }
  119. public WebSocketHelper()
  120. {
  121. Init();
  122. }
  123. }
  124. }

3.Program

目前并没有写入太多功能,只是加了控制台输入文字,然后转发给所有连接的用户

代码

  1. using WebSocket;
  2. namespace WebSocketNet6
  3. {
  4. internal class Program
  5. {
  6. private static List<string> IPList = new List<string>();
  7. private static WebSocketHelper WebSocketHelpers = new WebSocketHelper();
  8. static void Main(string[] args)
  9. {
  10. WebSocketHelpers.OnOpen += WebSocketHelper_OnOpen;
  11. WebSocketHelpers.OnClose += WebSocketHelper_OnClose;
  12. WebSocketHelpers.OnMessage += WebSocketHelper_OnMessage;
  13. while (true)
  14. {
  15. //监听控制台的输入
  16. string? contetn = Console.ReadLine();
  17. if (contetn != null)
  18. {
  19. Relay(contetn);
  20. if (contetn.Equals("q"))
  21. {
  22. WebSocketHelpers.CloseAllConnect();
  23. Console.WriteLine("关闭所有客户端的连接");
  24. break;
  25. }
  26. }
  27. Thread.Sleep(10);
  28. }
  29. }
  30. #region WebSocket回调
  31. //当收到消息
  32. private static void WebSocketHelper_OnMessage(string ip, string msg)
  33. {
  34. for (int i = 0; i < IPList.Count; i++)
  35. {
  36. if (IPList[i] != ip)
  37. {
  38. WebSocketHelpers.Send(IPList[i], msg);
  39. }
  40. }
  41. }
  42. //当客户端断开连接
  43. private static void WebSocketHelper_OnClose(string ip)
  44. {
  45. if (IPList.Contains(ip))
  46. {
  47. IPList.Remove(ip);
  48. }
  49. }
  50. //当客户端连接上服务器
  51. private static void WebSocketHelper_OnOpen(string ip)
  52. {
  53. if (!IPList.Contains(ip))
  54. {
  55. IPList.Add(ip);
  56. }
  57. }
  58. #endregion
  59. //转发所有客户端
  60. private static void Relay(string content)
  61. {
  62. if (IPList.Count == 0) return;
  63. for (int i = 0; i < IPList.Count; i++)
  64. {
  65. WebSocketHelpers.Send(IPList[i], content);
  66. }
  67. }
  68. }
  69. }

三、客户端

1.html

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <html>
  3. <head>
  4. <title>websocket client</title>
  5. <script type="text/javascript">
  6. var start = function () {
  7. var inc = document.getElementById('incomming');
  8. var wsImpl = window.WebSocket || window.MozWebSocket;
  9. var form = document.getElementById('sendForm');
  10. var input = document.getElementById('sendText');
  11. inc.innerHTML += "连接服务器..<br/>";
  12. // 创建一个新的websocket并连接
  13. window.ws = new wsImpl('ws://localhost:30000/');
  14. // 当数据来自服务器时,将调用此方法
  15. ws.onmessage = function (evt) {
  16. inc.innerHTML += ("[来自服务器的消息] " + evt.data + '<br/>');
  17. console.log("[来自服务器的消息] " + evt.data);
  18. };
  19. // 当建立连接时,将调用此方法
  20. ws.onopen = function () {
  21. inc.innerHTML += '已建立连接.. <br/>';
  22. };
  23. // 当连接关闭时,将调用此方法
  24. ws.onclose = function () {
  25. inc.innerHTML += '连接已关闭.. <br/>';
  26. }
  27. form.addEventListener('submit', function (e) {
  28. e.preventDefault();
  29. var val = input.value;
  30. ws.send(val);
  31. input.value = "";
  32. });
  33. }
  34. window.onload = start;
  35. </script>
  36. </head>
  37. <body>
  38. <form id="sendForm">
  39. <span>输入内容按回车发送消息</span> <br/>
  40. <input id="sendText" placeholder="Text to send" />
  41. </form>
  42. <pre id="incomming"></pre>
  43. </body>
  44. </html>

在本地新建一个 文本文档,将名字改为 index.html ,然后将上面的代码复制进去。

先打开上面的 Webscoket 服务器,用浏览器打开 index.html,

然后服务器端就会收到对于的消息了

服务器发送 你好

同样的,网页端也收到了来自服务器的消息

那么这样,就完成了网页端的通信了

2.Winform

新建一个 winform 项目

先安装插件 SuperSocket.ClientEngine

再安装插件 WebSocket4Net

新建脚本 WSocketClient.cs

  1. using SuperSocket.ClientEngine;
  2. using System;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using WebSocket4Net;
  6. namespace WebSocketClient
  7. {
  8. public class WSocketClient : IDisposable
  9. {
  10. //收到消息后的回调
  11. //public event Action<string> MessageReceived;
  12. public Action<string> MessageReceived;
  13. private WebSocket4Net.WebSocket _webSocket;
  14. /// <summary>
  15. /// 检查重连线程
  16. /// </summary>
  17. Thread _thread;
  18. bool _isRunning = false;
  19. /// <summary>
  20. /// 是否在运行中
  21. /// </summary>
  22. public bool IsRunning => _isRunning;
  23. /// <summary>
  24. /// WebSocket连接地址
  25. /// </summary>
  26. public string ServerPath { get; set; }
  27. public WSocketClient(string url)
  28. {
  29. ServerPath = url;
  30. this._webSocket = new WebSocket4Net.WebSocket(url);
  31. this._webSocket.Opened += WebSocket_Opened;
  32. this._webSocket.Error += WebSocket_Error;
  33. this._webSocket.Closed += WebSocket_Closed;
  34. this._webSocket.MessageReceived += WebSocket_MessageReceived;
  35. }
  36. /// <summary>
  37. /// 连接方法
  38. /// <returns></returns>
  39. public bool Start()
  40. {
  41. bool result = true;
  42. try
  43. {
  44. this._webSocket.Open();
  45. this._isRunning = true;
  46. this._thread = new Thread(new ThreadStart(CheckConnection));
  47. this._thread.Start();
  48. }
  49. catch (Exception ex)
  50. {
  51. Console.WriteLine(ex.ToString());
  52. result = false;
  53. this._isRunning = false;
  54. }
  55. return result;
  56. }
  57. /// <summary>
  58. /// 消息收到事件
  59. /// </summary>
  60. /// <param name="sender"></param>
  61. /// <param name="e"></param>
  62. private void WebSocket_MessageReceived(object sender, MessageReceivedEventArgs e)
  63. {
  64. Console.WriteLine("Received:" + e.Message);
  65. if (MessageReceived != null)
  66. MessageReceived(e.Message);
  67. }
  68. /// <summary>
  69. /// Socket关闭事件
  70. /// </summary>
  71. /// <param name="sender"></param>
  72. /// <param name="e"></param>
  73. private void WebSocket_Closed(object sender, EventArgs e)
  74. {
  75. Console.WriteLine("websocket_Closed");
  76. }
  77. /// <summary>
  78. /// Socket报错事件
  79. /// </summary>
  80. /// <param name="sender"></param>
  81. /// <param name="e"></param>
  82. private void WebSocket_Error(object sender, ErrorEventArgs e)
  83. {
  84. Console.WriteLine("websocket_Error:" + e.Exception.ToString());
  85. }
  86. /// <summary>
  87. /// Socket打开事件
  88. /// </summary>
  89. /// <param name="sender"></param>
  90. /// <param name="e"></param>
  91. private void WebSocket_Opened(object sender, EventArgs e)
  92. {
  93. Console.WriteLine("websocket_Opened");
  94. }
  95. /// <summary>
  96. /// 检查重连线程
  97. /// </summary>
  98. private void CheckConnection()
  99. {
  100. do
  101. {
  102. try
  103. {
  104. if (this._webSocket.State != WebSocket4Net.WebSocketState.Open && this._webSocket.State != WebSocket4Net.WebSocketState.Connecting)
  105. {
  106. Console.WriteLine("Reconnect websocket WebSocketState:" + this._webSocket.State);
  107. this._webSocket.Close();
  108. this._webSocket.Open();
  109. Console.WriteLine("正在重连");
  110. }
  111. }
  112. catch (Exception ex)
  113. {
  114. Console.WriteLine(ex.ToString());
  115. }
  116. System.Threading.Thread.Sleep(5000);
  117. } while (this._isRunning);
  118. }
  119. /// <summary>
  120. /// 发送消息
  121. /// </summary>
  122. /// <param name="Message"></param>
  123. public void SendMessage(string Message)
  124. {
  125. Task.Factory.StartNew(() =>
  126. {
  127. if (_webSocket != null && _webSocket.State == WebSocket4Net.WebSocketState.Open)
  128. {
  129. this._webSocket.Send(Message);
  130. }
  131. });
  132. }
  133. public void Dispose()
  134. {
  135. try
  136. {
  137. _thread?.Abort();
  138. }
  139. catch (Exception ex)
  140. {
  141. Console.WriteLine(ex.Message);
  142. }
  143. this._webSocket.Close();
  144. this._webSocket.Dispose();
  145. this._webSocket = null;
  146. this._isRunning = false;
  147. }
  148. }
  149. }

winfrom 界面如下

Form1.cs

  1. using System;
  2. using System.Windows.Forms;
  3. using WebSocketClient;
  4. namespace WinFormWebsocket
  5. {
  6. public partial class Form1 : Form
  7. {
  8. private static string url = "ws://127.0.0.1:30000";
  9. private WSocketClient client = new WSocketClient(url);
  10. public Form1()
  11. {
  12. InitializeComponent();
  13. }
  14. private void Form1_Load(object sender, EventArgs e)
  15. {
  16. Control.CheckForIllegalCrossThreadCalls = false;
  17. txtServerIP.Text = url;
  18. client.MessageReceived = MessageReceived;
  19. this.Text = "客户端";
  20. }
  21. private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  22. {
  23. if(client.IsRunning)
  24. client.Dispose();
  25. }
  26. /// <summary>
  27. /// 连接服务器
  28. /// </summary>
  29. /// <param name="sender"></param>
  30. /// <param name="e"></param>
  31. private void btnConnect_Click(object sender, EventArgs e)
  32. {
  33. try
  34. {
  35. if(client.IsRunning)
  36. {
  37. AddOrdinaryLog("已经连接服务器,不能重复执行");
  38. return;
  39. }
  40. bool result = client.Start();
  41. AddOrdinaryLog("连接是否成功:" + result);
  42. }
  43. catch (Exception ex)
  44. {
  45. string err = string.Format("连接失败:{0}", ex.Message);
  46. Console.WriteLine(err);
  47. throw;
  48. }
  49. }
  50. /// <summary>
  51. /// 关闭服务器
  52. /// </summary>
  53. /// <param name="sender"></param>
  54. /// <param name="e"></param>
  55. private void btnClose_Click(object sender, EventArgs e)
  56. {
  57. if (!client.IsRunning)
  58. {
  59. AddOrdinaryLog("服务器未连接");
  60. return;
  61. }
  62. // 记得释放资源否则会造成堆栈
  63. client.Dispose();
  64. AddOrdinaryLog("连接已关闭");
  65. }
  66. /// <summary>
  67. /// 发送消息
  68. /// </summary>
  69. /// <param name="sender"></param>
  70. /// <param name="e"></param>
  71. private void btnSendMsg_Click(object sender, EventArgs e)
  72. {
  73. string inputMsg = txtInputMsg.Text;
  74. if (string.IsNullOrEmpty(inputMsg))
  75. {
  76. MessageBox.Show("输入框不能为空");
  77. return;
  78. }
  79. client.SendMessage(inputMsg);
  80. AddOrdinaryLog(inputMsg);
  81. txtInputMsg.Text = string.Empty;
  82. }
  83. /// <summary>
  84. /// 服务端返回的消息
  85. /// </summary>
  86. private void MessageReceived(string msg)
  87. {
  88. AddOrdinaryLog(msg);
  89. }
  90. /// <summary>
  91. /// 添加日志
  92. /// </summary>
  93. /// <param name="content"></param>
  94. private void AddOrdinaryLog(string content)
  95. {
  96. //读取当前ListBox列表长度
  97. int len = ListBox_OrdinaryLogList.Items.Count;
  98. //插入新的一行
  99. ListBox_OrdinaryLogList.Items.Insert(len, content);
  100. //列表长度大于30,那么就删除第1行的数据
  101. if (len > 30)
  102. ListBox_OrdinaryLogList.Items.RemoveAt(0);
  103. //插入新的数据后,将滚动条移动到最下面
  104. int visibleItems = ListBox_OrdinaryLogList.ClientSize.Height / ListBox_OrdinaryLogList.ItemHeight;
  105. ListBox_OrdinaryLogList.TopIndex = Math.Max(ListBox_OrdinaryLogList.Items.Count - visibleItems + 1, 0);
  106. }
  107. }
  108. }

到这里,所有的准备工作都做完了,下面就来测试一下效果吧。

首先,运行 WebSocket 服务器端,再运行客户端,点击连接按钮

服务器端也显示有客户端连接上了。

那么现在用客户端发送消息,输入恭喜发财,然后点击 发送消息 按钮,这时历史消息列表就有对于的记录。

这时,服务器端也同样的收到了来自客户端的消息。

接下来,我们用服务器向客户端发送消息,在控制台输入文字后,按回车,会自动发送

客户端收到了来自服务器的消息

 

 这样,就完成了通讯部分的基本功能了。

 源码:点击下载

结束

如果这个帖子对你有用,欢迎 关注 + 点赞 + 留言,谢谢

end

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/164666
推荐阅读
相关标签
  

闽ICP备14008679号