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

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

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 相关类

  /// <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客户端示例

<!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服务器及多客户端连接的方式,希望对大家有所帮助。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • C#里SuperSocket库不能发现命令的原因

    在使用SuperSocket来写服务器的过程中,这是一个非常快速的开发方式,也非常好用.不过学习的曲线有点高,在使用的过程中经常会遇到各种各样的问题. 比如当下就遇到一个比较奇怪的问题,明明在项目里添加了命令,但是框架发现不了,这样就比较怪异了. 由于SuperSocket是使用反射的机制来查找命令,并且是跨不同的程序集. 因此SuperSocket对命令的发现有一定要求,同时要满足下面几个条件: 1.继承CommandBase类. 2.采用public声明. 3.在EXE程序集里,如果不在就需

  • asp.net平台下C#实现Socket通信

    TCP/IP:Transmission Control Protocol/Internet Protocol,传输控制协议/因特网互联协议,又名网络通讯协议.简单来说:TCP控制传输数据,负责发现传输的问题,一旦有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地,而IP是负责给因特网中的每一台电脑定义一个地址,以便传输.从协议分层模型方面来讲:TCP/IP由:网络接口层(链路层).网络层.传输层.应用层.它和OSI的七层结构以及对于协议族不同,下图简单表示: 注:最上的图示:TC

  • C#使用Socket快速判断数据库连接是否正常的方法

    本文实例讲述了C#使用Socket快速判断数据库连接是否正常的方法.分享给大家供大家参考.具体分析如下: 大家在做项目的时候,一般都是和数据库有关的.而相信许多人在用代码打开数据库的时候,没有判断数据库连接是否成功.如果写对了还好,但是出错了,会等老长时间(默认15s,不过 实际响应 可能会更长).而且还会出现卡死的情况,给用户的感觉就会变得非常差劲.所以快速判断数据库连接是否成功,就显得尤为重要了.   一般情况下,如果连接字符串正确,那么连接到数据库用的时间一般在5s以内.所以我们可以在连接

  • c# socket心跳超时检测的思路(适用于超大量TCP连接情况下)

    假设一种情景: TCP服务器有1万个客户端连接,如果客户端5秒钟不发数据,则要断开.服务端如何检测客户端是否超时?这看起来是一个非常简单的问题,其实不然! 最简单的处理方法是: 启动一个线程,每隔一段时间,检查每个连接是否超时.每次处理需要1万次检查.计算量太大!检查的时间间隔不能太小,否则大大增加计算量:如果间隔时间太大,超时误差会增大. 本文提出一种新颖的处理方法,就是针对这个看似简单而不易解决的问题!(以下用socket表示一个客户端连接) 1 内存布局图 假设socket3有新的数据到达

  • C# Socket连接请求超时机制实现代码分享

    .Net的System.Net.Sockets.TcpClient和System.Net.Sockets.Socket都没有直接为Connect/BeginConnect提供超时控制机制.因此,当服务器未处于监听状态,或者发生网络故障时,客户端连接请求会被迫等待很长一段时间,直到抛出异常.默认的等待时间长达20~30s..Net Socket库的SocketOptionName.SendTimeout提供了控制发送数据的超时时间,但并非本文讨论的连接请求的超时时间.实现 下面是实现的关键代码:

  • C#中的Socket编程详解

    目录 一,网络基础 二,Socket 对象 SocketType ProtocolType AddressFamily 三,Bind() 绑定与 Connect() 连接 Bind() Connect() 四,Listen() 监听请求连接 和 Accept() 接收连接请求 Listen() Accept() 五,Receive() 与 Send() Receive() 参数 返回 Send() 六,释放资源 close() 七,IPAddress 和IPEndPoint IPAddress

  • C#基于Socket套接字的网络通信封装

    本文为大家分享了C#基于Socket套接字的网络通信封装代码,供大家参考,具体内容如下 摘要 之所以要进行Socket套接字通信库封装,主要是直接使用套接字进行网络通信编程相对复杂,特别对于初学者而言.实际上微软从.net 2.0开始已经提供了TCP.UDP通信高级封装类如下: TcpListener TcpClient UdpClient 微软从.net 4.0开始提供基于Task任务的异步通信接口.而直接使用socket封装库,很多socket本身的细节没办法自行控制,本文目就是提供一种so

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

    服务端代码[控制台示例] 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.Addr

  • Java聊天室之实现运行服务器与等待客户端连接

    目录 一.题目描述 二.解题思路 三.代码详解 一.题目描述 题目实现:运行服务器程序,等待客户端程序连接. 二.解题思路 首先需要在服务器中建立服务器套接字,并等待客户程序的连接. 创建一个类:ServerSocketFrame,继承JFrame 通过ServerSocket类创建绑定到指定端口的服务器套接字对象.然后调用ServerSocket类的accept()方法监听客户端的连接. 实例化Socket对象 server = new ServerSocket(9527); // 可指定端口

  • Java编程Socket实现多个客户端连接同一个服务端代码

    Java Socket(套接字)通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过"套接字"向网络发出请求或者应答网络请求. 使用Socket实现多个客户端和同一客户端通讯:首先客户端连接服务端发送一条消息,服务端接收到消息后进行处理,完成后再回复客户端一条消息.本人通过自己的思维编写了一份服务端和客户端实现的代码,望能与大家相互学习,共同进步. 服务端代码 /** * Socket服务端 * 功能说明: * */ public cl

  • Golang 实现Thrift客户端连接池方式

    1 前言 阅读文章之前,请先了解一下thrift相关知识.thrift官方并没有提供客户端连接池的实现方案,而我们在实际使用时,thrift客户端必须复用,来保证较为可观的吞吐量,并避免在高QPS调用情况下,不断的创建.释放客户端所带来的机器端口耗尽问题. 本文会详细讲解如何实现一个简单可靠的thrift客户端连接池,并通过对照实验来说明thrift客户端连接池所带来的好处. 由于篇幅的原因,本文只粘出关键代码,源代码请查看Thrift Client Pool Demo 1.1 运行环境 Gol

  • Python基于socket实现TCP/IP客户和服务器通信

    前言 套接字除了用于分析网络地址等功能之外,还可以配置一个服务器,监听到来的消息. 比如你在网络上跟网络机器人聊天,你发送数据到机器人(服务器),然后机器人(服务器)反馈聊天数据信息给你. 当然,机器人的回复内容可能还涉及机器学习,但简单的消息反馈涉及的就是套接字的知识. 简单的搭建服务器与客户端 既然已经了解了套接字的应用.下面,我们来实现一个简单的单向通信TCP/IP服务器与客户端. 服务器 服务器的原理如下: 首先创建一个套接字,TCP是面向流的套接字.故需要使用SOCK_STREAM 然

  • php简单socket服务器客户端代码实例

    本篇文章分享一个简单的socket示例,用php.实现一个接收输入字符串,处理并返回这个字符串到客户端的TCP服务. 产生一个 socket 服务端 <?php /*文件名:socket_server.php*/ // 设置一些基本的变量 $host="127.0.0.1";//Socket运行的服务器的IP地址 $port=1234;//Socket运行的服务器的端口,端口取值为1到65535之间的数字,前提是这个端口未被使用 // 设置超时时间,这里设置为永不超时,确保PHP

  • 利用PHP如何实现Socket服务器

    socket服务器的工作方式是这样的,不间断地运行以等待客户端的连接.一旦客户端连接上了,服务器就会将它添加到客户名单中,然后开始等待来自客户端的消息. 不要走开,下面是完整的源代码: // Set time limit to indefinite execution set_time_limit (0); // Set the ip and port we will listen on $address = 'localhost'; $port = 10000; $max_clients =

  • 使用C#来编写一个异步的Socket服务器

    介绍 我最近需要为一个.net项目准备一个内部线程通信机制. 项目有多个使用ASP.NET,Windows 表单和控制台应用程序的服务器和客户端构成. 考虑到实现的可能性,我下定决心要使用原生的socket,而不是许多.NET中已经提前为我们构建好的组件, 像是所谓的管道, NetTcpClient 还有 Azure 服务总线. 这篇文章中的服务器基于System.Net.Sockets类异步方法. 这些允许你支持大量的socket客户端, 而一个客户端的连接是唯一的阻塞机制. 阻塞的时间是可以

  • PostgreSQL数据库服务端监听设置及客户端连接方法教程

    众所周知,PostgreSQL 是一个自由的对象-关系数据库服务器(数据库管理系统),是一个可以免费使用的开放源代码数据库系统.本文详细介绍了PostgreSQL数据库服务端监听设置及客户端连接方法,具体如下: 一.背景介绍: 本文所述PostgreSQL服务端运行在RedHat Linux上,IP为:192.168.230.128 客户端安装在Windows XP上, IP为:192.168.230.1 二.配置方法: 1.修改服务端/opt/postgresql/data/postgresq

  • DB2新手使用的一些小笔记:新建实例、数据库路径不存在、客户端连接 .

    首先,是添加数据库实例: DB2的实例之间是相互独立的,实例可以被看作是数据库的容器.而默认DB2装好后会自己建一个名为DB2的实例.我们这里需要新建一个,命令这样敲: 在db2的命令行工具里面打开命令行,然后输入: 复制代码 代码如下: db2icrt INSTNAME 它这个实例名还挺恶心的,必须是小于8个字符的名字. 再用命令行创建好以后才能用那个控制中心的添加实例的功能来添加刚才创建的实例.其实这个添加只是把已有的实例添加到GUI的控制中心里,而不是创建实例....所以,必须注意的是,在

随机推荐