C# socket异步 服务端
转自: http://blog.csdn.net/qq_20282263/article/details/54310737
- private Dictionary<string, Session> SessionPool = new Dictionary<string, Session>();
- private Dictionary<string, string> MsgPool = new Dictionary<string, string>();
- #region 启动WebSocket服务
- /// <summary>
- /// 启动WebSocket服务
- /// </summary>
- public void start(int port)
- {
- Socket SockeServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- SockeServer.Bind(new IPEndPoint(IPAddress.Any, port));
- SockeServer.Listen();
- SockeServer.BeginAccept(new AsyncCallback(Accept), SockeServer);
- Console.WriteLine("服务已启动");
- Console.WriteLine("按任意键关闭服务");
- Console.ReadLine();
- }
- #endregion
- #region 处理客户端连接请求
- /// <summary>
- /// 处理客户端连接请求
- /// </summary>
- /// <param name="result"></param>
- private void Accept(IAsyncResult socket)
- {
- // 还原传入的原始套接字
- Socket SockeServer = (Socket)socket.AsyncState;
- // 在原始套接字上调用EndAccept方法,返回新的套接字
- Socket SockeClient = SockeServer.EndAccept(socket);
- byte[] buffer = new byte[];
- try
- {
- //接收客户端的数据
- SockeClient.BeginReceive(buffer, , buffer.Length, SocketFlags.None, new AsyncCallback(Recieve), SockeClient);
- //保存登录的客户端
- Session session = new Session();
- session.SockeClient = SockeClient;
- session.IP = SockeClient.RemoteEndPoint.ToString();
- session.buffer = buffer;
- lock (SessionPool)
- {
- if (SessionPool.ContainsKey(session.IP))
- {
- this.SessionPool.Remove(session.IP);
- }
- this.SessionPool.Add(session.IP, session);
- }
- //准备接受下一个客户端
- SockeServer.BeginAccept(new AsyncCallback(Accept), SockeServer);
- Console.WriteLine(string.Format("Client {0} connected", SockeClient.RemoteEndPoint));
- }
- catch (Exception ex)
- {
- Console.WriteLine("Error : " + ex.ToString());
- }
- }
- #endregion
- #region 处理接收的数据
- /// <summary>
- /// 处理接受的数据
- /// </summary>
- /// <param name="socket"></param>
- private void Recieve(IAsyncResult socket)
- {
- Socket SockeClient = (Socket)socket.AsyncState;
- string IP = SockeClient.RemoteEndPoint.ToString();
- if (SockeClient == null || !SessionPool.ContainsKey(IP))
- {
- return;
- }
- try
- {
- int length = SockeClient.EndReceive(socket);
- byte[] buffer = SessionPool[IP].buffer;
- SockeClient.BeginReceive(buffer, , buffer.Length, SocketFlags.None, new AsyncCallback(Recieve), SockeClient);
- string msg = Encoding.UTF8.GetString(buffer, , length);
- // websocket建立连接的时候,除了TCP连接的三次握手,websocket协议中客户端与服务器想建立连接需要一次额外的握手动作
- if (msg.Contains("Sec-WebSocket-Key"))
- {
- SockeClient.Send(PackageHandShakeData(buffer, length));
- SessionPool[IP].isWeb = true;
- return;
- }
- if (SessionPool[IP].isWeb)
- {
- msg = AnalyzeClientData(buffer, length);
- }
- byte[] msgBuffer = PackageServerData(msg);
- foreach (Session se in SessionPool.Values)
- {
- se.SockeClient.Send(msgBuffer, msgBuffer.Length, SocketFlags.None);
- }
- }
- catch
- {
- SockeClient.Disconnect(true);
- Console.WriteLine("客户端 {0} 断开连接", IP);
- SessionPool.Remove(IP);
- }
- }
- #endregion
- #region 客户端和服务端的响应
- /*
- * 客户端向服务器发送请求
- *
- * GET / HTTP/1.1
- * Origin: http://localhost:1416
- * Sec-WebSocket-Key: vDyPp55hT1PphRU5OAe2Wg==
- * Connection: Upgrade
- * Upgrade: Websocket
- *Sec-WebSocket-Version: 13
- * User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
- * Host: localhost:8064
- * DNT: 1
- * Cache-Control: no-cache
- * Cookie: DTRememberName=admin
- *
- * 服务器给出响应
- *
- * HTTP/1.1 101 Switching Protocols
- * Upgrade: websocket
- * Connection: Upgrade
- * Sec-WebSocket-Accept: xsOSgr30aKL2GNZKNHKmeT1qYjA=
- *
- * 在请求中的“Sec-WebSocket-Key”是随机的,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个魔幻字符串
- * “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”。使用 SHA-1 加密,之后进行 BASE-64编码,将结果做为 “Sec-WebSocket-Accept” 头的值,返回给客户端
- */
- #endregion
- #region 打包请求连接数据
- /// <summary>
- /// 打包请求连接数据
- /// </summary>
- /// <param name="handShakeBytes"></param>
- /// <param name="length"></param>
- /// <returns></returns>
- private byte[] PackageHandShakeData(byte[] handShakeBytes, int length)
- {
- string handShakeText = Encoding.UTF8.GetString(handShakeBytes, , length);
- string key = string.Empty;
- Regex reg = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
- Match m = reg.Match(handShakeText);
- if (m.Value != "")
- {
- key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
- }
- byte[] secKeyBytes = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
- string secKey = Convert.ToBase64String(secKeyBytes);
- var responseBuilder = new StringBuilder();
- responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + "\r\n");
- responseBuilder.Append("Upgrade: websocket" + "\r\n");
- responseBuilder.Append("Connection: Upgrade" + "\r\n");
- responseBuilder.Append("Sec-WebSocket-Accept: " + secKey + "\r\n\r\n");
- return Encoding.UTF8.GetBytes(responseBuilder.ToString());
- }
- #endregion
- #region 处理接收的数据
- /// <summary>
- /// 处理接收的数据
- /// 参考 http://www.cnblogs.com/smark/archive/2012/11/26/2789812.html
- /// </summary>
- /// <param name="recBytes"></param>
- /// <param name="length"></param>
- /// <returns></returns>
- private string AnalyzeClientData(byte[] recBytes, int length)
- {
- int start = ;
- // 如果有数据则至少包括3位
- if (length < ) return "";
- // 判断是否为结束针
- bool IsEof = (recBytes[start] >> ) > ;
- // 暂不处理超过一帧的数据
- if (!IsEof) return "";
- start++;
- // 是否包含掩码
- bool hasMask = (recBytes[start] >> ) > ;
- // 不包含掩码的暂不处理
- if (!hasMask) return "";
- // 获取数据长度
- UInt64 mPackageLength = (UInt64)recBytes[start] & 0x7F;
- start++;
- // 存储4位掩码值
- byte[] Masking_key = new byte[];
- // 存储数据
- byte[] mDataPackage;
- if (mPackageLength == )
- {
- // 等于126 随后的两个字节16位表示数据长度
- mPackageLength = (UInt64)(recBytes[start] << | recBytes[start + ]);
- start += ;
- }
- if (mPackageLength == )
- {
- // 等于127 随后的八个字节64位表示数据长度
- mPackageLength = (UInt64)(recBytes[start] << ( * ) | recBytes[start] << ( * ) | recBytes[start] << ( * ) | recBytes[start] << ( * ) | recBytes[start] << ( * ) | recBytes[start] << ( * ) | recBytes[start] << | recBytes[start + ]);
- start += ;
- }
- mDataPackage = new byte[mPackageLength];
- for (UInt64 i = ; i < mPackageLength; i++)
- {
- mDataPackage[i] = recBytes[i + (UInt64)start + ];
- }
- Buffer.BlockCopy(recBytes, start, Masking_key, , );
- for (UInt64 i = ; i < mPackageLength; i++)
- {
- mDataPackage[i] = (byte)(mDataPackage[i] ^ Masking_key[i % ]);
- }
- return Encoding.UTF8.GetString(mDataPackage);
- }
- #endregion
- #region 发送数据
- /// <summary>
- /// 把发送给客户端消息打包处理(拼接上谁什么时候发的什么消息)
- /// </summary>
- /// <returns>The data.</returns>
- /// <param name="message">Message.</param>
- private byte[] PackageServerData(string msg)
- {
- byte[] content = null;
- byte[] temp = Encoding.UTF8.GetBytes(msg);
- if (temp.Length < )
- {
- content = new byte[temp.Length + ];
- content[] = 0x81;
- content[] = (byte)temp.Length;
- Buffer.BlockCopy(temp, , content, , temp.Length);
- }
- else if (temp.Length < 0xFFFF)
- {
- content = new byte[temp.Length + ];
- content[] = 0x81;
- content[] = ;
- content[] = (byte)(temp.Length & 0xFF);
- content[] = (byte)(temp.Length >> & 0xFF);
- Buffer.BlockCopy(temp, , content, , temp.Length);
- }
- return content;
- }
- #endregion
- Session
- public class Session
- {
- private Socket _sockeclient;
- private byte[] _buffer;
- private string _ip;
- private bool _isweb = false;
- public Socket SockeClient
- {
- set { _sockeclient = value; }
- get { return _sockeclient; }
- }
- public byte[] buffer
- {
- set { _buffer = value; }
- get { return _buffer; }
- }
- public string IP
- {
- set { _ip = value; }
- get { return _ip; }
- }
- public bool isWeb
- {
- set { _isweb = value; }
- get { return _isweb; }
- }
- }
C# socket异步 服务端的更多相关文章
- java socket实现服务端,客户端简单网络通信。Chat
之前写的实现简单网络通信的代码,有一些严重bug.后面详细写. 根据上次的代码,主要增加了用户注册,登录页面,以及实现了实时显示当前在登录状态的人数.并解决一些上次未发现的bug.(主要功能代码参见之 ...
- 【gRPC】C++异步服务端优化版,多服务接口样例
官方的C++异步服务端API样例可读性并不好,理解起来非常的费劲,各种状态机也并不明了,整个运行过程也容易读不懂,因此此处参考网上的博客进行了重写,以求顺利读懂. C++异步服务端实例,详细注释版 g ...
- Socket客户端/服务端简单实例
1.client端 package demo.socket; import java.io.BufferedReader;import java.io.IOException;import java. ...
- java.net.SocketException:Software caused connection abort: recv failed 异常分析 +socket客户端&服务端代码
java.net.SocketException:Software caused connection abort: recv failed 异常分析 分类: 很多的技术 2012-01-04 12: ...
- JAVA Socket获取服务端信息
1.Socket.getInetAddress(),获取服务端地址. 2.Socket.getPort(),获取服务端端口.
- 简单的同步Socket程序服务端
首先,Socket是.Net提供的 System.Net.Sockets命名空间的Scoket类为网络通信提供了一套丰富的方法和属性 服务器按照Socket的基本流程 先创建Socket 在用Bind ...
- c#Socket Tcp服务端编程
创建一个socket服务类,绑定监听端口, 然后创建一个线程listen连接的客户端, 把监听到的客户端加入dictionary里面,以便于管理, 同时创建receive线程,循环接收数据加入list ...
- python网络编程:socket、服务端、客户端
本文内容: socket介绍 TCP: 服务端 客户端 UDP: 服务端 客户端 首发时间:2018-02-08 01:14 修改: 2018-03-20 :重置了布局,增加了UDP 什么是socke ...
- 利用Socket 客户端---->服务端 传送文件到指定路径,并返回一个友好的回馈
首先盲写的一个传输文件的方法,但测试发现了一个非常不容易发现的问题,这里先说明一下. 错误的代码如下: package com.TCP.java; import java.io.File; impor ...
随机推荐
- C#读操作(字节/字符)Filestream、File、StreamReader
方法一:使用Filestream,将文本一次性全部转换为字节,之后转换为string显示在text中 OpenFileDialog fd = new OpenFileDialog(); fd.Filt ...
- Java代码执行顺序及多态体现
/** * Description: * 基类的引用变量可以只想基类的实例对象也可指向其子类的事来对象 * 接口的引用变量也可以指向实现类的实例对象 * 程序调用的方法在运行期才动态绑定 * 绑定指将 ...
- 04: redis集群
1.1 主从同步 1.CPA原理 1. CPA原理是分布式存储理论的基石: C(一致性): A(可用性): P(分区容忍性); 2. 当主从网络无法连通时,修改操作无法同步到节点,所以“一致性” ...
- Python 入门 之 类的约束以及super()剖析
Python 入门 之 类的约束以及super()剖析 1.类的约束 第一版: class WechatPay: def pay(self): print("微信支付") clas ...
- Web前端开发HTML基础
HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记),相当于定义统一的一套规则,大家都来遵守他,这样就可以让浏览器根据标 ...
- Oracle Help 类
public static string ConnString = @"Data Source=xxx;USER ID=xxx;PASSWORD=xxx"; /// <sum ...
- java 问题汇总
1.自动加载出错 require a bean of .... The injection point has the following annotations: - @org.springfram ...
- 一份非常完整、详细的MySQL规范
一.数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名 ...
- Stream 分布式数据流的轻量级异步快照
1. 概述 分布式有状态流处理支持在云中部署和执行大规模连续计算,主要针对低延迟和高吞吐量.这种模式的一个最根本的挑战就是在可能的失败情况下提供处理保证.现有方法依赖于可用于故障恢复的周期性全局状态快 ...
- webpack4 打包
1. 基本安装及命令 npm config set registry https://registry.npm.taobao.org // 淘宝镜像npm install webpack-c ...