通讯编程入门--WEBSOCKET

C#通讯编程入门--WEBSOCKET

WebSocket服务端 C#示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Text.RegularExpressions;
using System.Security.Cryptography;

namespace WebSocketDemo
{
    class Program
    {
        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("等待客户端连接....");
                Socket sc = listener.Accept();//接受一个连接
                Console.WriteLine("接受到了客户端:" + sc.RemoteEndPoint.ToString() + "连接....");

                //握手
                int length = sc.Receive(buffer);//接受客户端握手信息
                sc.Send(PackHandShakeData(GetSecKeyAccetp(buffer, length)));
                Console.WriteLine("已经发送握手协议了....");

                //接受客户端数据
                Console.WriteLine("等待客户端数据....");
                length = sc.Receive(buffer);//接受客户端信息
                string clientMsg = AnalyticData(buffer, length);
                Console.WriteLine("接受到客户端数据:" + clientMsg);

                //发送数据
                string sendMsg = "您好," + clientMsg;
                Console.WriteLine("发送数据:“" + sendMsg + "” 至客户端....");
                sc.Send(PackData(sendMsg));

                Console.WriteLine("演示Over!");

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        /// <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);
            //如果把上一行换成下面两行,才是thewebsocketprotocol-17协议,但居然握手不成功,目前仍没弄明白!
            //responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine);
            //responseBuilder.Append("Sec-WebSocket-Protocol: chat" + 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;
        }
    }
}

HTML5 客户端示例代码

<!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>

参考博客:WebSocket

原文地址:https://www.cnblogs.com/developer-ios/p/8410588.html

时间: 2024-10-22 03:03:59

通讯编程入门--WEBSOCKET的相关文章

COM编程入门不得不看的文章:第二部分 深入COM服务器

原文:http://www.codeproject.com/Articles/901/Introduction-to-COM-Part-II-Behind-the-Scenes-of-a 本文为刚刚接触COM的程序员提供编程指南,解释COM服务器内幕以及如何用C++编写自己的接口(前一篇博文主要是COM编程的入门:COM编程入门不得不看的文章 :第一部分 什么是COM,如何使用COM).继上一篇COM编程入门之后,本文将讨论有关COM服务器的内容,解释编写自己的COM接口和COM服务器所需要的步

编程入门——工具初识、数据类型转换、数字类型

编程入门   零.引言 当我们学习一门语言时,最开始的是从一段代码开始,而书写和运行代码是从认识语言和使用工具展开.一个好的工具能对启蒙者有着寓意深远的影响.那么怎么界定一个好的工具选择呢? 一.工具初识 1.计算机语言:含义:指用于人与计算机之间的通讯语言. 计算机系统最大特征是指令通过一种语言传达给机器.为了使电子计算机进行各种工作,就需要有一套用以编写计算机程序的数字.字符.和语言规划,由这些字符和语法规则组成计算机指令(或各种语句).这些就是计算机能接受的语言.二进制是计算机使用的一种计

[转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么? http://www.52im.net/thread-1732-1-1.html 1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机网络编程的基础,TCP/UDP收发消息都靠它.我们熟悉的web服务器底层依赖它,我们用到的MySQL关系数据库.Redis内存数据库底层依赖它.我们用微信和别

[转帖]脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手 http://www.52im.net/thread-1729-1-1.html 1.引言 网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一.很多读者都知道"三次"和"四次",但是如果问深入一点,他们往往都无法作出准确回答. 本篇文章尝试使用动画图片的方式,来对这个知识点进行"脑残式"讲解(哈哈),期望读者们可以更加简单.直观地理解TCP网络通信交互的本

《鸡啄米C++编程入门系列》系列技术文章整理收藏

<鸡啄米C++编程入门系列>系列技术文章整理收藏 收藏整理鸡啄米C++编程入门系列文章,供个人和网友学习C++时参考 1鸡啄米:C++编程入门系列之前言 2鸡啄米:C++编程入门系列之一(进制数) 3鸡啄米:C++编程入门系列之二(原码.反码与补码) 4鸡啄米:C++编程入门系列之三(VS2010的使用介绍) 5鸡啄米:C++编程入门系列之四(数据类型) 6鸡啄米:C++编程入门系列之五(运算符和表达式) 7鸡啄米:C++编程入门系列之六(算法的基本控制结构之选择结构) 8鸡啄米:C++编程入

编程入门指南

前言 如今编程成为了一个越来越重要的「技能」:作为设计师,懂一些编程可能会帮你更好地理解自己的工作内容:作为创业者,技术创始人的身份则会让你的很多工作显得更容易.而作为刚想入门的新手,面对眼前海量的信息,或许根本不知道从哪里开始:入门轻松度过初级材料的学习后,发现学习越来越困难,陡峭的学习曲线又让你望而却步:你知道如何在页面上打印输出一些文本行,但是你不知道何时该进行一个真正的有用的项目:你不清楚自己还有哪些不知道的东西,你甚至搞不清下一步该学什么. 这篇文章的内容对此不仅会有一些方向性的建议,

CUDA C编程入门-介绍

CUDA C编程入门-介绍 1.1.从图形处理到通用并行计算 在实时.高清3D图形的巨大市场需求的驱动下,可编程的图形处理单元或者GPU发展成拥有巨大计算能力的和非常高的内存带宽的高度并行的.多线程的.多核处理器.如图1和图2所示. 图 1 CPU和GPU每秒的浮点计算次数 图 2 CPU和GPU的内存带宽 在CPU和GPU之间在浮点计算能力上的差异的原因是GPU专做密集型计算和高度并行计算-恰好是图形渲染做的-因此设计成这样,更多的晶体管用于数据处理而不是数据缓存和流控制,如图3所示. 图 3

Android jni 编程入门

本文将介绍如何使用eclipse和ndk-build来编写一个基于Android4.4版本的包含有.so动态库的安卓程序. 前提是已经安装和配置好了诸如SDK,NDK等编译环境.下面开始编程! 1 程序逻辑 我们要编写的程序包含两部分:java部分--负责界面和调用JNI native函数:JNI native 部分--负责native函数的具体实现(本文使用C语言). native 函数伪代码如下: ? 1 2 3 4 5 6 7 8 /* funtion: 传入两个整形变量,计算他们之和 r

[转] C#.Net Socket网络通讯编程总结

1.理解socket1).Socket接口是TCP/IP网络的应用程序接口(API).Socket接口定义了许多函数和例程,程序员可以用它们来开发TCP/IP网络应用程序.Socket可以看成是网络通信上的一个端点,也就是说,网络通信包括两台主机或两个进程,通过网络传递它们之间的数据.为了进行网络通信,程序在网络对话的每一端都需要一个Socket. 2).TCP/IP传输层使用协议端口将数据传送给一台主机的特定应用程序,从网络的观点看,协议端口是一个应用程序的进程地址.当传输层模块的网络软件模块