首页 > 代码库 > C# Socket学习笔记二
C# Socket学习笔记二
小记:昨天咱们已经了解了Socket的通信原理,可是点对点的一次通信并不是我们想要的,那么今天那我们就继续学习异步通信,简单来说就是服务器端和客户端可以进行多次 互发信息的通信而不用担心通道会关闭。在介绍异步通信时,客户端和服务器端的连接和上面介绍的同步通信建立连接的方式是一样的,只是接收和发送数据的方式改变了!
1.什么是异步通信?
异步:客户端请求之后,不必等到服务器回应之后就可以发送下一条请求,并行运行。
2.同步与异步的区别?
同步:我叫你吃饭,你若暂时有事情我就一直在那等,不干别的事情,直到你忙完。
异步:我叫你吃饭,你若暂时有事情,我就先撤,干点别的,你忙完了再通过某种方式,如电话,通知我。
异步通信的好处我理解的就是可以多次使用一个Socket增加网络的吞吐量,提高资源的利用率。
下面开始代码分析,和上篇的没多大差别,就是发送和接收数据的方式变了:
服务器端:TcpServer.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Net; 7 using System.Net.Sockets; 8 using System.Threading; 9 10 11 namespace TcpServer 12 { 13 class Program 14 { 15 public static Socket serverSocket; 16 public static Thread thread; 17 18 static void Main(string[] args) 19 { 20 //确定端口号 21 int port = 6000; 22 23 //设定连接IP 24 string host = "127.0.0.1"; 25 26 //将IP地址字符串转化为IP地址实例 27 IPAddress ip = IPAddress.Parse(host); 28 29 //将网络端点表示为 IP 地址和端口号 30 IPEndPoint ipe = new IPEndPoint(ip, port); 31 32 //建立Socket 33 //addressFamily 参数一指定 Socket 类使用的寻址方案 34 //socketType 参数二指定 Socket 类的类型 35 //protocolType 参数三指定 Socket 使用的协议。 36 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 37 38 39 //socket与本地终结点建立关联 40 socket.Bind(ipe); 41 string strSend = "HelloClient"; 42 //开始监听端口 43 socket.Listen(10); 44 Console.WriteLine("服务端已开启,等待客户端连接.....\t" + DateTime.Now.ToString() + DateTime.Now.Millisecond.ToString()); 45 46 //为新建的连接建立新的Socket目的为客户端将要建立连接 47 serverSocket = socket.Accept(); 48 Console.WriteLine("连接已建立......\t\t" + DateTime.Now.ToString() + DateTime.Now.Millisecond.ToString()); 49 Console.WriteLine("客户端->服务端:\t" + serverSocket.RemoteEndPoint + "->" + serverSocket.LocalEndPoint); 50 51 //while (true) 52 { 53 string recStr =string.Empty; 54 //定义缓冲区用于接收客户端的数据 55 byte[] recbyte = new byte[1024]; 56 57 //开始接收数据 58 ReceiveData(); 59 60 //服务端给客户端回送消息 61 strSend = "HelloClient"; 62 63 //服务端发送数据 64 //strSend = Console.ReadLine(); 65 Send(strSend); 66 67 //开启线程监视客户端是否断开 68 thread = new Thread(ClientConnectOrNot); 69 Thread.Sleep(0); 70 thread.Start(); 71 72 73 //serverSocket.Close(); 74 Console.ReadLine(); 75 } 76 } 77 78 /// <summary> 79 /// 监视客户端是否断开 80 /// </summary> 81 public static void ClientConnectOrNot() 82 { 83 //Console.WriteLine(serverSocket.Poll(-1, SelectMode.SelectRead)); 84 if (serverSocket.Poll(-1, SelectMode.SelectRead) == true)//客户端断开 85 { 86 Console.WriteLine(serverSocket.RemoteEndPoint + "断开了连接"); 87 thread.Abort(); 88 89 } 90 else 91 { 92 Console.WriteLine(thread.ThreadState); 93 } 94 } 95 #region 96 /// <summary> 97 /// 异步连接 98 /// </summary> 99 /// <param name="ip"></param>100 /// <param name="port"></param>101 /// <param name="clientSocket"></param>102 public static void Connect(IPAddress ip, int port)103 {104 serverSocket.BeginConnect(ip, port, new AsyncCallback(ConnectCallback), serverSocket);105 }106 107 private static void ConnectCallback(IAsyncResult ar)108 {109 try110 {111 Socket handler = (Socket)ar.AsyncState;112 handler.EndConnect(ar);113 }114 catch (SocketException ex)115 {116 throw ex;117 }118 }119 /// <summary>120 /// 发送数据121 /// </summary>122 /// <param name="data"></param>123 public static void Send(string data)124 {125 //Send(System.Text.Encoding.UTF8.GetBytes(data));126 //解决中文乱码127 Send(UTF8Encoding.UTF8.GetBytes(data));128 129 //byte[] byteData = http://www.mamicode.com/UTF8Encoding.UTF8.GetBytes(data);>130 //Send(Encoding.ASCII.GetBytes(data));131 }132 /// <summary>133 /// 发送数据134 /// </summary>135 /// <param name="byteData"></param>136 private static void Send(byte[] byteData)137 {138 try139 {140 int length = byteData.Length;141 //byte[] head = BitConverter.GetBytes(length); //这个为什么不对,我也不清楚142 byte[] head = Encoding.ASCII.GetBytes(length.ToString()); //将发送数据的字节长度写到报头中143 //head.Length = 4; //开始我想指定头部4个字节长度用来存放字节的总数便于拆包144 byte[] data = http://www.mamicode.com/new byte[head.Length + byteData.Length]; //发送包的总大小145 for (int i = 0; i < 3; i++)146 {147 data[i] = 0;148 }149 Array.Copy(head, data, head.Length); //将head复制到data中150 Array.Copy(byteData, 0, data, head.Length, byteData.Length); //将byteData复制到data中151 152 serverSocket.BeginSend(data, 0, data.Length, 0, new AsyncCallback(SendCallback), serverSocket);153 }154 catch (SocketException ex)155 {156 throw ex;157 }158 }159 160 private static void SendCallback(IAsyncResult ar)161 {162 try163 {164 Socket handler = (Socket)ar.AsyncState;165 handler.EndSend(ar);166 }167 catch (SocketException ex)168 {169 throw ex;170 }171 }172 173 /// <summary>174 /// 接收数据8个字节175 /// </summary>176 static byte[] MsgBuffer = new byte[8];177 178 /// <summary>179 /// 接收消息180 /// </summary>181 public static void ReceiveData()182 {183 serverSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallback), null);184 }185 186 /// <summary>187 /// 回调接收数据188 /// </summary>189 /// <param name="ar"></param>190 private static void ReceiveCallback(IAsyncResult ar)191 {192 try193 {194 int REnd = serverSocket.EndReceive(ar);195 if (REnd > 0)196 {197 byte[] data = http://www.mamicode.com/new byte[REnd];198 Array.Copy(MsgBuffer, 0, data, 0, REnd);199 int Msglen = data.Length;200 //在此次可以对data进行按需处理201 serverSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallback), null);202 Console.WriteLine("来自到客户端{0}字节:{1} \tTime:{2}",REnd ,UTF8Encoding .UTF8.GetString(data, 0, Msglen),DateTime.Now.ToString()+ DateTime.Now.Millisecond.ToString());203 }204 else205 {206 dispose();207 }208 }209 catch (SocketException ex)210 {211 throw ex;212 }213 }214 215 /// <summary>216 /// 释放连接217 /// </summary>218 private static void dispose()219 {220 try221 {222 serverSocket.Shutdown(SocketShutdown.Both);223 serverSocket.Close();224 }225 catch (Exception ex)226 {227 throw ex;228 }229 }230 #endregion231 }232 }
客户端 TcpClient.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Net; 7 using System.Net.Sockets; 8 using System.Threading; 9 10 namespace TcpClient 11 { 12 class Program 13 { 14 static int port = 6000; //监听端口号 15 static string host = "127.0.0.1"; //连接服务端IP 16 static IPAddress ip = IPAddress.Parse(host); //将IP地址转换为IP实例 17 static IPEndPoint ipe = new IPEndPoint(ip, port);//将网络端点表示为 IP 地址和端口号 18 static Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//建立客户端Socket 19 20 static Thread thread_client; 21 static void Main(string[] args) 22 { 23 Connect(ip, port);//异步连接 24 string sendStr = "Nice to meet you,Server!"; 25 thread_client = new Thread(ClientConnectOrNot); 26 Thread.Sleep(0); 27 thread_client.Start(); 28 { 29 Console.WriteLine("服务器->客户端:" + clientSocket.RemoteEndPoint + "->" + clientSocket.LocalEndPoint); 30 Send(sendStr); //发送消息 31 ReceiveData(); //接收消息 32 sendStr = Console.ReadLine(); 33 } 34 35 } 36 /// <summary> 37 /// 判断服务端是否关闭 38 /// </summary> 39 public static void ClientConnectOrNot() 40 { 41 if (clientSocket.Poll(-1, SelectMode.SelectRead) == true) //检测服务端是否关闭 42 { 43 Console.WriteLine(clientSocket.RemoteEndPoint+"服务端已关闭..."); 44 45 //thread_client.Abort(); 46 //Thread exit = new Thread(ApplicationExit); //自动关闭程序 47 //Thread.Sleep(3000); 48 //exit.Start(); 49 50 } 51 else 52 { 53 Console.WriteLine(thread_client.ThreadState); 54 } 55 } 56 /// <summary> 57 /// 退出程序关闭Dos窗口 58 /// </summary> 59 public static void ApplicationExit() 60 { 61 Environment.Exit(0); 62 } 63 64 #region 65 /// <summary> 66 /// 异步连接 67 /// </summary> 68 /// <param name="ip"></param> 69 /// <param name="port"></param> 70 /// <param name="clientSocket"></param> 71 public static void Connect(IPAddress ip, int port) 72 { 73 clientSocket.BeginConnect(ip, port, new AsyncCallback(ConnectCallback), clientSocket); 74 } 75 76 private static void ConnectCallback(IAsyncResult ar) 77 { 78 try 79 { 80 Socket handler = (Socket)ar.AsyncState; 81 handler.EndConnect(ar); 82 } 83 catch (SocketException ex) 84 { 85 throw ex; 86 } 87 } 88 /// <summary> 89 /// 发送数据 90 /// </summary> 91 /// <param name="data"></param> 92 public static void Send(string data) 93 { 94 //Send(System.Text.Encoding.UTF8.GetBytes(data)); 95 //Send(Encoding.ASCII.GetBytes(data)); 96 Send(UTF8Encoding.UTF8.GetBytes(data)); 97 } 98 /// <summary> 99 /// 发送数据100 /// </summary>101 /// <param name="byteData"></param>102 private static void Send(byte[] byteData)103 {104 try105 {106 int length = byteData.Length;107 //byte[] head = BitConverter.GetBytes(length);108 byte[] head = Encoding.ASCII.GetBytes(length.ToString()); //头部表示字节的总长度109 byte[] data = http://www.mamicode.com/new byte[head.Length + byteData.Length];110 Array.Copy(head, data, head.Length);111 Array.Copy(byteData, 0, data, head.Length, byteData.Length);112 clientSocket.BeginSend(data, 0, data.Length, 0, new AsyncCallback(SendCallback), clientSocket);113 }114 catch (SocketException ex)115 { }116 }117 /// <summary>118 /// 回调发送119 /// </summary>120 /// <param name="ar"></param>121 private static void SendCallback(IAsyncResult ar)122 {123 try124 {125 Socket handler = (Socket)ar.AsyncState;126 handler.EndSend(ar);127 }128 catch (SocketException ex)129 {130 throw ex;131 }132 }133 134 /// <summary>135 /// 定义缓冲区接收数据8个字节136 /// </summary>137 static byte[] MsgBuffer = new byte[8];138 139 /// <summary>140 /// 接收消息141 /// </summary>142 public static void ReceiveData()143 {144 clientSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallback), null);145 }146 static bool first = true;147 private static void ReceiveCallback(IAsyncResult ar)148 {149 try150 {151 int REnd = clientSocket.EndReceive(ar);152 if (REnd > 0)153 {154 byte[] data = http://www.mamicode.com/new byte[REnd];155 Array.Copy(MsgBuffer, 0, data, 0, REnd);156 157 int Msglen = data.Length;158 //在此次可以对data进行按需处理159 160 clientSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallback), null);161 string revStr = UTF8Encoding .UTF8.GetString(data, 0, Msglen);162 if (first)163 {164 string len = revStr.Substring(0, 2);165 first = false;166 }167 Console.WriteLine("来自服务端{0}字节:{1}\tTime:{2}",REnd,revStr,DateTime.Now.ToString()+ DateTime.Now.Millisecond.ToString());168 }169 else170 {171 dispose();172 }173 }174 catch (SocketException ex)175 { }176 }177 /// <summary>178 /// 释放Socket179 /// </summary>180 private static void dispose()181 {182 try183 {184 clientSocket.Shutdown(SocketShutdown.Both);185 clientSocket.Close();186 }187 catch (Exception ex)188 {189 throw ex;190 }191 }192 #endregion193 }194 }
先打开服务端:
开始->运行,输入cmd确定再输入netstat -a 查看端口监听状态
接下来运行客户端:
下面咱们稍微改下代码,使客户端和服务端能进行数据交互。
服务器端:
开始进行会话了,
客户端:你好吗?
服务端:我很好,你呢?
客户端:I‘m fine too!
咱么断开客户端,看看你服务端的反应:
若是断开服务端:
总结:实验发现异步通信可以利用一个Socket进行多次数据传输,自己定义的缓冲区用于接收数据,如果定义的缓冲区很大不会发生拆包现象,如果很小则会自动按缓冲区大小分割。
C# Socket学习笔记二
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。