服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#实现Socket服务器及多客户端连接的方式

C#实现Socket服务器及多客户端连接的方式

2022-12-22 14:42痕迹g C#

这篇文章介绍了C#实现Socket服务器及多客户端连接的方式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

服务端代码[控制台示例]

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
static List<Socket> Sockets = new List<Socket>();
        static void Main(string[] args)
        {
            int port = 10;
            byte[] buffer = new byte[1024];
 
            IPEndPoint localEP = new IPEndPoint(IPAddress.Any, port);
            Socket listener = new Socket(localEP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
 
            try
            {
                listener.Bind(localEP);
                listener.Listen(10);
                Console.WriteLine("等待客户端连接....");
                while (true) //该操作用于多个客户端连接
                {
                    Socket sc = listener.Accept();//接受一个连接
                    Sockets.Add(sc); //将连接的客户端, 添加到内存当中
                    Thread t = new Thread(new ThreadStart(() => ReceiveData(sc))); //开启当前Socket线程, 去执行获取数据的动作,与客户端通信
                    t.IsBackground = true;
                    t.Start();
                }
 
 
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            Console.ReadLine();
        }
 
        public static void ReceiveData(Socket sc)
        {
            byte[] buffer = new byte[1024];
            Console.WriteLine("接受到了客户端:" + sc.RemoteEndPoint.ToString() + "连接....");
            //握手
            int length = sc.Receive(buffer);//接受客户端握手信息
            sc.Send(PackHandShakeData(GetSecKeyAccetp(buffer, length)));while (true)
            {
                try
                {
                    //接受客户端数据
                    Console.WriteLine("等待客户端数据....");
                    length = sc.Receive(buffer);//接受客户端信息
                    string clientMsg = AnalyticData(buffer, length);
                    Console.WriteLine("接受到客户端数据:" + clientMsg);
                    //发送数据
                    string sendMsg = "服务端返回信息:" + clientMsg;
                    sc.Send(PackData(sendMsg));
                }
                catch (Exception ex)
                {
                    Sockets.Remove(sc);  //如果接收的过程中,断开, 那么内存中移除当前Socket对象, 并且退出当前线程
                    Console.WriteLine("客户端已经断开连接!");
                    return;
                }
            }
        }

Socket 相关类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/// <summary>
      /// 打包握手信息
      /// </summary>
      /// <param name="secKeyAccept"></param>
      /// <returns></returns>
      private static byte[] PackHandShakeData(string secKeyAccept)
      {
          var responseBuilder = new StringBuilder();
          responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine);
          responseBuilder.Append("Upgrade: websocket" + Environment.NewLine);
          responseBuilder.Append("Connection: Upgrade" + Environment.NewLine);
          responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine + Environment.NewLine);
          return Encoding.UTF8.GetBytes(responseBuilder.ToString());
      }
 
      /// <summary>
      /// 生成Sec-WebSocket-Accept
      /// </summary>
      /// <param name="handShakeText">客户端握手信息</param>
      /// <returns>Sec-WebSocket-Accept</returns>
      private static string GetSecKeyAccetp(byte[] handShakeBytes, int bytesLength)
      {
          string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, bytesLength);
          string key = string.Empty;
          Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
          Match m = r.Match(handShakeText);
          if (m.Groups.Count != 0)
          {
              key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
          }
          byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
          return Convert.ToBase64String(encryptionString);
      }
 
      /// <summary>
      /// 解析客户端数据包
      /// </summary>
      /// <param name="recBytes">服务器接收的数据包</param>
      /// <param name="recByteLength">有效数据长度</param>
      /// <returns></returns>
      private static string AnalyticData(byte[] recBytes, int recByteLength)
      {
          if (recByteLength < 2) { return string.Empty; }
 
          bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最后一帧 
          if (!fin)
          {
              return string.Empty;// 超过一帧暂不处理
          }
 
          bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码 
          if (!mask_flag)
          {
              return string.Empty;// 不包含掩码的暂不处理
          }
 
          int payload_len = recBytes[1] & 0x7F; // 数据长度 
 
          byte[] masks = new byte[4];
          byte[] payload_data;
 
          if (payload_len == 126)
          {
              Array.Copy(recBytes, 4, masks, 0, 4);
              payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]);
              payload_data = new byte[payload_len];
              Array.Copy(recBytes, 8, payload_data, 0, payload_len);
 
          }
          else if (payload_len == 127)
          {
              Array.Copy(recBytes, 10, masks, 0, 4);
              byte[] uInt64Bytes = new byte[8];
              for (int i = 0; i < 8; i++)
              {
                  uInt64Bytes[i] = recBytes[9 - i];
              }
              UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0);
 
              payload_data = new byte[len];
              for (UInt64 i = 0; i < len; i++)
              {
                  payload_data[i] = recBytes[i + 14];
              }
          }
          else
          {
              Array.Copy(recBytes, 2, masks, 0, 4);
              payload_data = new byte[payload_len];
              Array.Copy(recBytes, 6, payload_data, 0, payload_len);
 
          }
 
          for (var i = 0; i < payload_len; i++)
          {
              payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]);
          }
 
          return Encoding.UTF8.GetString(payload_data);
      }
      
      /// <summary>
      /// 打包服务器数据
      /// </summary>
      /// <param name="message">数据</param>
      /// <returns>数据包</returns>
      private static byte[] PackData(string message)
      {
          byte[] contentBytes = null;
          byte[] temp = Encoding.UTF8.GetBytes(message);
 
          if (temp.Length < 126)
          {
              contentBytes = new byte[temp.Length + 2];
              contentBytes[0] = 0x81;
              contentBytes[1] = (byte)temp.Length;
              Array.Copy(temp, 0, contentBytes, 2, temp.Length);
          }
          else if (temp.Length < 0xFFFF)
          {
              contentBytes = new byte[temp.Length + 4];
              contentBytes[0] = 0x81;
              contentBytes[1] = 126;
              contentBytes[2] = (byte)(temp.Length & 0xFF);
              contentBytes[3] = (byte)(temp.Length >> 8 & 0xFF);
              Array.Copy(temp, 0, contentBytes, 4, temp.Length);
          }
          else
          {
              // 暂不处理超长内容 
          }
 
          return contentBytes;
      }

客户端连接[网页测试]

WebSocket客户端示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebSockets客户端示例</title>
</head>
<script>
var webSocket;
function connect()
{
    try
    {
        var readyState = new Array("正在连接","已建立连接","正在关闭连接","已关闭连接");
        var host = "ws://localhost:10";
        webSocket = new WebSocket(host);
        var message = document.getElementById("message");
        message.innerHTML +="<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
        webSocket.onopen = function()
        {
            message.innerHTML += "<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
        }
        webSocket.onmessage = function(msg)
        {
            message.innerHTML +="<p>接收信息:" + msg.data + "</p>";
        }
        webSocket.onclose=function()
        {
            message.innerHTML +="<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
        }
    }
    catch(exception)
    {
        message.innerHTML += "<p>有错误发生</p>";
    }
}
function send()
{
    var text = document.getElementById("text").value;
    var message = document.getElementById("message");
    if(text == "")
    {
        message.innerHTML += "<p>请输入一些文字</p>";
        return ;
    }
    try
    {
        webSocket.send(text);
        message.innerHTML += "<p>发送数据:" +text + "</p>";
    }
    catch(exception)
    {
        message.innerHTML += "<p>发送数据出错</p>";
    }
    document.getElementById("text").value="";
}
function disconnect()
{
    webSocket.close();
}
</script>
<body>
<h1>WebSocket客户端示例</h1>
<div id="message"></div>
<p>请输入一些文字</p>
<input id="text" type="text">
<button id="connect" onClick="connect();">建立连接</button>
<button id="send" onClick="send();">发送数据</button>
<button id="disconnect" onClick="disconnect();">断开连接</button>
</body>
</html>

以上所述是小编给大家介绍的C#实现Socket服务器及多客户端连接的方式,希望对大家有所帮助。在此也非常感谢大家对服务器之家网站的支持!

原文链接:https://www.cnblogs.com/zh7791/p/11151787.html

延伸 · 阅读

精彩推荐
  • C#C# Soap调用WebService的实例

    C# Soap调用WebService的实例

    下面小编就为大家带来一篇C# Soap调WebService的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    梦想总是这么遥远5232022-02-16
  • C#C#编程自学之开篇介绍

    C#编程自学之开篇介绍

    这篇是一篇关于C#编程自学的入门文章,学习C#的开始,开启了C#的奇妙之旅,感兴趣的小伙伴们可以持续关注系列文章。...

    C#教程网12162021-10-28
  • C#C#通过html调用WinForm的方法

    C#通过html调用WinForm的方法

    这篇文章主要介绍了C#通过html调用WinForm的方法,涉及html页面中使用JavaScript访问C#的相关技巧,需要的朋友可以参考下...

    且行且思8192021-11-18
  • C#unity中点击某一个按钮播放某一个动作的操作

    unity中点击某一个按钮播放某一个动作的操作

    这篇文章主要介绍了unity中点击某一个按钮播放某一个动作的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    梦见晗4142022-11-11
  • C#Unity ScrollView实现动态列表生成

    Unity ScrollView实现动态列表生成

    这篇文章主要为大家详细介绍了Unity ScrollView实现动态列表生成,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    wdear040110962022-09-05
  • C#简单实现winform编辑器

    简单实现winform编辑器

    这篇文章主要教大家如何简单实现winform编辑器,功能很简单,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    忧叹ic5742022-01-20
  • C#Visual Studio 未能加载各种Package包的解决方案

    Visual Studio 未能加载各种Package包的解决方案

    打开Visual Studio 的时候,总提示未能加载相应的Package包,有时候还无法打开项目,各种错误提示,怎么解决呢?下面小编给大家带来了Visual Studio 未能加载...

    jianxuanbing9902021-12-08
  • C#C#中读写INI配置文件的方法

    C#中读写INI配置文件的方法

    这篇文章主要介绍了C#中读写INI配置文件的方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下...

    郝光明7052022-02-25