C# socket异步 服务端

转自:  http://blog.csdn.net/qq_20282263/article/details/54310737

  1       private Dictionary<string, Session> SessionPool = new Dictionary<string, Session>();
  2         private Dictionary<string, string> MsgPool = new Dictionary<string, string>();
  3
  4         #region 启动WebSocket服务
  5         /// <summary>
  6         /// 启动WebSocket服务
  7         /// </summary>
  8         public void start(int port)
  9         {
 10             Socket SockeServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 11             SockeServer.Bind(new IPEndPoint(IPAddress.Any, port));
 12             SockeServer.Listen(20);
 13             SockeServer.BeginAccept(new AsyncCallback(Accept), SockeServer);
 14             Console.WriteLine("服务已启动");
 15             Console.WriteLine("按任意键关闭服务");
 16             Console.ReadLine();
 17         }
 18         #endregion
 19
 20         #region 处理客户端连接请求
 21         /// <summary>
 22         /// 处理客户端连接请求
 23         /// </summary>
 24         /// <param name="result"></param>
 25         private void Accept(IAsyncResult socket)
 26         {
 27             // 还原传入的原始套接字
 28             Socket SockeServer = (Socket)socket.AsyncState;
 29             // 在原始套接字上调用EndAccept方法,返回新的套接字
 30             Socket SockeClient = SockeServer.EndAccept(socket);
 31             byte[] buffer = new byte[4096];
 32             try
 33             {
 34                 //接收客户端的数据
 35                 SockeClient.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Recieve), SockeClient);
 36                 //保存登录的客户端
 37                 Session session = new Session();
 38                 session.SockeClient = SockeClient;
 39                 session.IP = SockeClient.RemoteEndPoint.ToString();
 40                 session.buffer = buffer;
 41                 lock (SessionPool)
 42                 {
 43                     if (SessionPool.ContainsKey(session.IP))
 44                     {
 45                         this.SessionPool.Remove(session.IP);
 46                     }
 47                     this.SessionPool.Add(session.IP, session);
 48                 }
 49                 //准备接受下一个客户端
 50                 SockeServer.BeginAccept(new AsyncCallback(Accept), SockeServer);
 51                 Console.WriteLine(string.Format("Client {0} connected", SockeClient.RemoteEndPoint));
 52             }
 53             catch (Exception ex)
 54             {
 55                 Console.WriteLine("Error : " + ex.ToString());
 56             }
 57         }
 58         #endregion
 59
 60         #region 处理接收的数据
 61         /// <summary>
 62         /// 处理接受的数据
 63         /// </summary>
 64         /// <param name="socket"></param>
 65         private void Recieve(IAsyncResult socket)
 66         {
 67             Socket SockeClient = (Socket)socket.AsyncState;
 68             string IP = SockeClient.RemoteEndPoint.ToString();
 69             if (SockeClient == null || !SessionPool.ContainsKey(IP))
 70             {
 71                 return;
 72             }
 73             try
 74             {
 75                 int length = SockeClient.EndReceive(socket);
 76                 byte[] buffer = SessionPool[IP].buffer;
 77                 SockeClient.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Recieve), SockeClient);
 78                 string msg = Encoding.UTF8.GetString(buffer, 0, length);
 79                 //  websocket建立连接的时候,除了TCP连接的三次握手,websocket协议中客户端与服务器想建立连接需要一次额外的握手动作
 80                 if (msg.Contains("Sec-WebSocket-Key"))
 81                 {
 82                     SockeClient.Send(PackageHandShakeData(buffer, length));
 83                     SessionPool[IP].isWeb = true;
 84                     return;
 85                 }
 86                 if (SessionPool[IP].isWeb)
 87                 {
 88                     msg = AnalyzeClientData(buffer, length);
 89                 }
 90                 byte[] msgBuffer = PackageServerData(msg);
 91                 foreach (Session se in SessionPool.Values)
 92                 {
 93                     se.SockeClient.Send(msgBuffer, msgBuffer.Length, SocketFlags.None);
 94                 }
 95             }
 96             catch
 97             {
 98                 SockeClient.Disconnect(true);
 99                 Console.WriteLine("客户端 {0} 断开连接", IP);
100                 SessionPool.Remove(IP);
101             }
102         }
103         #endregion
104         #region 客户端和服务端的响应
105         /*
106          * 客户端向服务器发送请求
107          *
108          * GET / HTTP/1.1
109          * Origin: http://localhost:1416
110          * Sec-WebSocket-Key: vDyPp55hT1PphRU5OAe2Wg==
111          * Connection: Upgrade
112          * Upgrade: Websocket
113          *Sec-WebSocket-Version: 13
114          * User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
115          * Host: localhost:8064
116          * DNT: 1
117          * Cache-Control: no-cache
118          * Cookie: DTRememberName=admin
119          *
120          * 服务器给出响应
121          *
122          * HTTP/1.1 101 Switching Protocols
123          * Upgrade: websocket
124          * Connection: Upgrade
125          * Sec-WebSocket-Accept: xsOSgr30aKL2GNZKNHKmeT1qYjA=
126          *
127          * 在请求中的“Sec-WebSocket-Key”是随机的,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个魔幻字符串
128          * “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”。使用 SHA-1 加密,之后进行 BASE-64编码,将结果做为 “Sec-WebSocket-Accept” 头的值,返回给客户端
129          */
130         #endregion
131
132         #region 打包请求连接数据
133         /// <summary>
134         /// 打包请求连接数据
135         /// </summary>
136         /// <param name="handShakeBytes"></param>
137         /// <param name="length"></param>
138         /// <returns></returns>
139         private byte[] PackageHandShakeData(byte[] handShakeBytes, int length)
140         {
141             string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, length);
142             string key = string.Empty;
143             Regex reg = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
144             Match m = reg.Match(handShakeText);
145             if (m.Value != "")
146             {
147                 key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
148             }
149             byte[] secKeyBytes = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
150             string secKey = Convert.ToBase64String(secKeyBytes);
151             var responseBuilder = new StringBuilder();
152             responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + "\r\n");
153             responseBuilder.Append("Upgrade: websocket" + "\r\n");
154             responseBuilder.Append("Connection: Upgrade" + "\r\n");
155             responseBuilder.Append("Sec-WebSocket-Accept: " + secKey + "\r\n\r\n");
156             return Encoding.UTF8.GetBytes(responseBuilder.ToString());
157         }
158         #endregion
159
160         #region 处理接收的数据
161         /// <summary>
162         /// 处理接收的数据
163         /// 参考 http://www.cnblogs.com/smark/archive/2012/11/26/2789812.html
164         /// </summary>
165         /// <param name="recBytes"></param>
166         /// <param name="length"></param>
167         /// <returns></returns>
168         private string AnalyzeClientData(byte[] recBytes, int length)
169         {
170             int start = 0;
171             // 如果有数据则至少包括3位
172             if (length < 2) return "";
173             // 判断是否为结束针
174             bool IsEof = (recBytes[start] >> 7) > 0;
175             // 暂不处理超过一帧的数据
176             if (!IsEof) return "";
177             start++;
178             // 是否包含掩码
179             bool hasMask = (recBytes[start] >> 7) > 0;
180             // 不包含掩码的暂不处理
181             if (!hasMask) return "";
182             // 获取数据长度
183             UInt64 mPackageLength = (UInt64)recBytes[start] & 0x7F;
184             start++;
185             // 存储4位掩码值
186             byte[] Masking_key = new byte[4];
187             // 存储数据
188             byte[] mDataPackage;
189             if (mPackageLength == 126)
190             {
191                 // 等于126 随后的两个字节16位表示数据长度
192                 mPackageLength = (UInt64)(recBytes[start] << 8 | recBytes[start + 1]);
193                 start += 2;
194             }
195             if (mPackageLength == 127)
196             {
197                 // 等于127 随后的八个字节64位表示数据长度
198                 mPackageLength = (UInt64)(recBytes[start] << (8 * 7) | recBytes[start] << (8 * 6) | recBytes[start] << (8 * 5) | recBytes[start] << (8 * 4) | recBytes[start] << (8 * 3) | recBytes[start] << (8 * 2) | recBytes[start] << 8 | recBytes[start + 1]);
199                 start += 8;
200             }
201             mDataPackage = new byte[mPackageLength];
202             for (UInt64 i = 0; i < mPackageLength; i++)
203             {
204                 mDataPackage[i] = recBytes[i + (UInt64)start + 4];
205             }
206             Buffer.BlockCopy(recBytes, start, Masking_key, 0, 4);
207             for (UInt64 i = 0; i < mPackageLength; i++)
208             {
209                 mDataPackage[i] = (byte)(mDataPackage[i] ^ Masking_key[i % 4]);
210             }
211             return Encoding.UTF8.GetString(mDataPackage);
212         }
213         #endregion
214
215         #region 发送数据
216         /// <summary>
217         /// 把发送给客户端消息打包处理(拼接上谁什么时候发的什么消息)
218         /// </summary>
219         /// <returns>The data.</returns>
220         /// <param name="message">Message.</param>
221         private byte[] PackageServerData(string msg)
222         {
223             byte[] content = null;
224             byte[] temp = Encoding.UTF8.GetBytes(msg);
225             if (temp.Length < 126)
226             {
227                 content = new byte[temp.Length + 2];
228                 content[0] = 0x81;
229                 content[1] = (byte)temp.Length;
230                 Buffer.BlockCopy(temp, 0, content, 2, temp.Length);
231             }
232             else if (temp.Length < 0xFFFF)
233             {
234                 content = new byte[temp.Length + 4];
235                 content[0] = 0x81;
236                 content[1] = 126;
237                 content[2] = (byte)(temp.Length & 0xFF);
238                 content[3] = (byte)(temp.Length >> 8 & 0xFF);
239                 Buffer.BlockCopy(temp, 0, content, 4, temp.Length);
240             }
241             return content;
242         }
243         #endregion
Session
 1   public class Session
 2     {
 3         private Socket _sockeclient;
 4         private byte[] _buffer;
 5         private string _ip;
 6         private bool _isweb = false;
 7
 8         public Socket SockeClient
 9         {
10             set { _sockeclient = value; }
11             get { return _sockeclient; }
12         }
13
14         public byte[] buffer
15         {
16             set { _buffer = value; }
17             get { return _buffer; }
18         }
19
20         public string IP
21         {
22             set { _ip = value; }
23             get { return _ip; }
24         }
25
26         public bool isWeb
27         {
28             set { _isweb = value; }
29             get { return _isweb; }
30         }
31     }
时间: 2024-10-03 00:54:52

C# socket异步 服务端的相关文章

android通过socket连接服务端(PC端)

自己的计算机网络的基础太差了,一个很小的Demo居然搞了快一天,真醉了,不过坑踩多了,自然知道怎么走路了. 首先,是服务端的代码 class Server implements Runnable{ public static void main(){ Thread server = new Thread(new Server()); server.start();} //服务端因为需要接受多个客户端的信息,所以需要一直开放端口等待客户端连入,我就不写try catch了,有点多 public v

Cocos2dx3.x使用socket创建服务端和客户端改进

由于一个网友使用笔者写的SocketClient作为游戏客户端网络数据接收类,出现了一些问题 这个问题就是因为当执行onRecv时创建了一个Sprite(Sprite::create("1.png")),而创建完成后sprite的数据混乱,或者MoveTo时返回的也是混乱数据.原因在于在多线程申请内存,在主线程使用就会出现问题.为了解决这个问题,特意看了cocos2dx的WebSocket的实现方式,发现当接收到数据时并不是立即调用回调函数,而是将数据信息加入到消息队列,当主线程更新时

Socket通信服务端和客户端总结

服务端:1.创建一个Socket对象.用来侦听的.2.绑定端口和IP3.开启侦听4.开始接受客户端连接5.创建一个代理通信Socket对象.用来通信的.6.发送消息接收消息7.收到客户端的道别,也会回一个:我也走了8.关闭Socket 客户端:1.创建Socket对象2.连接服务器3.发送消息接受消息4.停止连接服务器和客户端都可以.发消息:我要走了.5.关闭Socket

java中socket创建服务端与客户端即时对聊

package tool; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; impo

java.net.SocketException:Software caused connection abort: recv failed 异常分析 +socket客户端&amp;服务端代码

java.net.SocketException:Software caused connection abort: recv failed 异常分析 分类: 很多的技术 2012-01-04 12:54 8004人阅读 评论(6) 收藏 举报 socket服务器bufferstring网络java 第 1个异常是java.net.BindException:Address already in use: JVM_Bind.该异常发生在服务器端进行new ServerSocket(port)(p

使用socket模拟服务端与客户端传输文件

package netFile; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.Socket; public class SocketTask { //客

11.网络编程:socket、服务端、客户端

socket: socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求. python中使用socket来进行网络连接传输 由图可知: socket中客户端需要进行的操作是:建立,连接,传输数据 ,接收数据,关闭连接 服务端需要进行的操作是:建立,绑定IP地址和端口,等待连接,接收数据,传输数据 ,关闭连接 服务端: 建立:socket.socket() 绑定端口:bind(('IP地址',端口)),其中地址和端口号是一个 tuple

java 界面编程用socket实现服务端与客户端的循环通信。

服务端: package 实验五聊天; import java.awt.BorderLayout; import java.awt.EventQueue; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.ne

socket创建服务端和客户端

看情况选择相对应的套接字*面向连接的传输--tcp协议--可靠的--流式套接字(SOCK_STREAM)*面向无连接的传输--udp协议--不可靠的--数据报套接字(SOCK_DGRAM) 在liunx中  telnet ip port 可以当成临时客服端 服务端示例: 创建服务端示例: from socket import * #创建套接字(参数:地址族类型,套接字类型,选定子协议类型) sockfd = socket(AF_INET,SOCK_STREAM,proto = 0) #绑定地址(