欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# Socket服务器及多客户端连接示例

程序员文章站 2022-12-05 15:26:58
服务端代码[控制台示例] 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;
        }

客户端连接[网页测试]
<!doctype html>



websockets客户端示例



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>