Socket编程 同步以及异步通信

转自 https://www.cnblogs.com/BLoodMaster/archive/2010/07/02/1769774.html

套接字简介:套接字最早是Unix的,window是借鉴过来的。TCP/IP协议族提供三种套接字:流式、数据报式、原始套接字。其中原始套接字允许对底层协议直接访问,一般用于检验新协议或者新设备问题,很少使用。

套接字编程原理:延续文件作用思想,打开-读写-关闭的模式。

C/S编程模式如下:

  • 服务器端:

打开通信通道,告诉本地机器,愿意在该通道上接受客户请求——监听,等待客户请求——接受请求,创建专用链接进行读写——处理完毕,关闭专用链接——关闭通信通道(当然其中监听到关闭专用链接可以重复循环)

  • 客户端:打开通信通道,连接服务器——数据交互——关闭信道。

Socket通信方式:

  • 同步:客户端在发送请求之后必须等到服务器回应之后才可以发送下一条请求。串行运行
  • 异步:客户端请求之后,不必等到服务器回应之后就可以发送下一条请求。并行运行

套接字模式:

  • 阻塞:执行此套接字调用时,所有调用函数只有在得到返回结果之后才会返回。在调用结果返回之前,当前进程会被挂起。即此套接字一直被阻塞在网络调用上。
  • 非阻塞:执行此套接字调用时,调用函数即使得不到得到返回结果也会返回。

套接字工作步骤:

  • 服务器监听:监听时服务器端套接字并不定位具体客户端套接字,而是处于等待链接的状态,实时监控网络状态
  • 客户端链接:客户端发出链接请求,要连接的目标是服务器端的套接字。为此客户端套接字必须描述服务器端套接字的服务器地址与端口号。
  • 链接确认:是指服务器端套接字监听到客户端套接字的链接请求时,它响应客户端链接请求,建立一个新的线程,把服务器端套接字的描述发送给客户端,一旦客户端确认此描述,则链接建立好。而服务器端的套接字继续处于监听状态,继续接受其他客户端套接字请求。

在TCP/IP网络中,IP网络交互分类两大类:面向连接的交互与面向无连接的交互。

 

 

Socket构造函数:public socket(AddressFamily 寻址类型, SocketType 套接字类型, ProtocolType 协议类型)。但需要注意的是套接字类型与协议类型并不是可以随便组合。

SocketType

ProtocolType

描述

Stream

Tcp

面向连接

Dgram

Udp

面向无连接

Raw

Icmp

网际消息控制

Raw

Raw

基础传输协议

Socket类的公共属性:

属性名

描述

AddressFamily

获取Socket的地址族

Available

获取已经从网络接收且可供读取的数据量

Blocking

获取或设置一个值,只是socket是否处于阻塞模式

Connected

获取一个值,指示当前连接状态

Handle

获取socket的操作系统句柄

LocalEndPoint

获取本地终端EndPoint

RemoteEndPoint

获取远程终端EndPoint

ProtocolType

获取协议类型

SocketType

获取SocketType类型

Socket常用方法:

Bind(EndPoint)

服务器端套接字需要绑定到特定的终端,客户端也可以先绑定再请求连接

Listen(int)

监听端口,其中parameters表示最大监听数

Accept()

接受客户端链接,并返回一个新的链接,用于处理同客户端的通信问题

Send()

发送数据

Send(byte[])

简单发送数据

Send(byte[],SocketFlag)

使用指定的SocketFlag发送数据

Send(byte[], int, SocketFlag)

使用指定的SocketFlag发送指定长度数据

Send(byte[], int, int, SocketFlag)

使用指定的SocketFlag,将指定字节数的数据发送到已连接的socket(从指定偏移量开始)

Receive()

接受数据

Receive(byte[])

简单接受数据

Receive (byte[],SocketFlag)

使用指定的SocketFlag接受数据

Receive (byte[], int, SocketFlag)

使用指定的SocketFlag接受指定长度数据

Receive (byte[], int, int, SocketFlag)

使用指定的SocketFlag,从绑定的套接字接收指定字节数的数据,并存到指定偏移量位置的缓冲区

Connect(EndPoint)

连接远程服务器

ShutDown(SocketShutDown)

禁用套接字,其中SocketShutDown为枚举,Send禁止发送,Receive为禁止接受,Both为两者都禁止

Close()

关闭套接字,释放资源

异步通信方法:

BeginAccept(AsynscCallBack,object)

开始一个一步操作接受一个连接尝试。参数:一个委托。一个对象。对象包含此请求的状态信息。其中回调方法中必须使用EndAccept方法。应用程序调用BegineAccept方法后,系统会使用单独的线程执行指定的回调方法并在EndAccept上一直处于阻塞状态,直至监测到挂起的链接。EndAccept会返回新的socket对象。供你来同远程主机数据交互。不能使用返回的这个socket接受队列中的任何附加连接。调用BeginAccept当希望原始线程阻塞的时候,请调用WaitHandle.WaitOne方法。当需要原始线程继续执行时请在回调方法中使用ManualResetEvent的set方法

BeginConnect(EndPoint, AsyncCallBack, Object)

回调方法中必须使用EndConnect()方法。Object中存储了连接的详细信息。

BeginSend(byte[], SocketFlag, AsyncCallBack, Object)

BegineReceive(byte[], SocketFlag, AsyncCallBack, Object)

BegineDisconnect(bool, AsyncCallBack, Object)

                 

给出同步通信与异步通信的示例:

同步通信:

预定义结构体,同步通信没有多线程异步委托回调,所以无需预定义结构体

客户端Client:

 1 class Program
 2 
 3 {
 4 
 5         static void Main()
 6 
 7         {
 8 
 9             try{
10 
11                 int port = 2000;
12 
13                 string host = "127.0.0.1";
14 
15                 IPAddress ip = IPAddress.Parse(host);
16 
17                 IPEndPoint ipe = new IPEndPoint(ip, port);//把ip和端口转化为IPEndPoint实例
18 
19                 Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);//创建一个Socket
20 
21                 Console.WriteLine("Conneting...");
22 
23                 c.Connect(ipe);//连接到服务器
24 
25                 string sendStr = "hello!This is a socket test";
26 
27                 byte[] bs = Encoding.ASCII.GetBytes(sendStr);
28 
29                 Console.WriteLine("Send Message");
30 
31                 c.Send(bs, bs.Length, 0);//发送测试信息
32 
33                 string recvStr = "";
34 
35                 byte[] recvBytes = new byte[1024];
36 
37                 int bytes;
38 
39                 bytes = c.Receive(recvBytes, recvBytes.Length, 0);//从服务器端接受返回信息
40 
41                 recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
42 
43                 Console.WriteLine("Client Get Message:{0}", recvStr);//显示服务器返回信息
44 
45                 c.Close();
46 
47             }
48 
49             catch (ArgumentNullException e){
50 
51                 Console.WriteLine("ArgumentNullException: {0}", e);
52 
53             }
54 
55             catch (SocketException e){
56 
57                 Console.WriteLine("SocketException: {0}", e);
58 
59             }
60 
61             Console.WriteLine("Press Enter to Exit");
62 
63             Console.ReadLine();
64 
65         }
66 
67 }
View Code

服务器端:

 1 class Program
 2 
 3 {
 4 
 5     static void Main()
 6 
 7     {
 8 
 9         try{
10 
11             int port = 2000;
12 
13             string host = "127.0.0.1";
14 
15             IPAddress ip = IPAddress.Parse(host);
16 
17             IPEndPoint ipe = new IPEndPoint(ip, port);
18 
19             Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);//创建一个Socket类
20 
21             s.Bind(ipe);//绑定2000端口
22 
23             s.Listen(0);//开始监听
24 
25             Console.WriteLine("Wait for connect");
26 
27             Socket temp = s.Accept();//为新建连接创建新的Socket。
28 
29             Console.WriteLine("Get a connect");
30 
31             string recvStr = "";
32 
33             byte[] recvBytes = new byte[1024];
34 
35             int bytes;
36 
37             bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//从客户端接受信息
38 
39             recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
40 
41             Console.WriteLine("Server Get Message:{0}", recvStr);//把客户端传来的信息显示出来
42 
43             string sendStr = "Ok!Client Send Message Sucessful!";
44 
45             byte[] bs = Encoding.ASCII.GetBytes(sendStr);
46 
47             temp.Send(bs, bs.Length, 0);//返回客户端成功信息
48 
49             temp.Close();
50 
51             s.Close();
52 
53         }
54 
55         catch (ArgumentNullException e){
56 
57             Console.WriteLine("ArgumentNullException: {0}", e);}
58 
59         catch (SocketException e){
60 
61             Console.WriteLine("SocketException: {0}", e);}
62 
63         Console.WriteLine("Press Enter to Exit");
64 
65         Console.ReadLine();
66 
67     }
68 
69 }
View Code

异步通信:

客户端Client:

预定义结构体,用于异步委托之间的传递。用户根据自己需要定制即可

  1 public class StateObject
  2 
  3 {
  4 
  5     // Client socket.
  6 
  7     public Socket workSocket = null;
  8 
  9     // Size of receive buffer.
 10 
 11     public const int BufferSize = 256;
 12 
 13     // Receive buffer.
 14 
 15     public byte[] buffer = new byte[BufferSize];
 16 
 17     // Received data string.
 18 
 19     public StringBuilder sb = new StringBuilder();
 20 
 21 }
 22 
 23 正文:
 24 
 25 public class AsynchronousClient
 26 
 27 {
 28 
 29     // The port number for the remote device.
 30 
 31     private const int port = 11000;
 32 
 33     // ManualResetEvent instances signal completion.
 34 
 35     private static ManualResetEvent connectDone = new ManualResetEvent(false);
 36 
 37     private static ManualResetEvent sendDone = new ManualResetEvent(false);
 38 
 39     private static ManualResetEvent receiveDone = new ManualResetEvent(false);
 40 
 41     // The response from the remote device.
 42 
 43 private static String response = String.Empty;
 44 
 45  
 46 
 47     private static void StartClient(){
 48 
 49         // Connect to a remote device.
 50 
 51         try{
 52 
 53             // Establish the remote endpoint for the socket.
 54 
 55             // The name of the remote device is "host.contoso.com".
 56 
 57             IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
 58 
 59             IPAddress ipAddress = ipHostInfo.AddressList[0];
 60 
 61             IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
 62 
 63  
 64 
 65             // Create a TCP/IP socket.
 66 
 67             Socket client = new Socket(AddressFamily.InterNetwork,
 68 
 69                 SocketType.Stream, ProtocolType.Tcp);
 70 
 71  
 72 
 73             // Connect to the remote endpoint.
 74 
 75             client.BeginConnect(remoteEP,
 76 
 77                 new AsyncCallback(ConnectCallback), client);
 78 
 79             connectDone.WaitOne();
 80 
 81  
 82 
 83             // Send test data to the remote device.
 84 
 85             Send(client, "This is a test<EOF>");
 86 
 87             sendDone.WaitOne();
 88 
 89  
 90 
 91             // Receive the response from the remote device.
 92 
 93             Receive(client);
 94 
 95             receiveDone.WaitOne();
 96 
 97  
 98 
 99             // Write the response to the console.
100 
101             Console.WriteLine("Response received : {0}", response);
102 
103  
104 
105             // Release the socket.
106 
107             client.Shutdown(SocketShutdown.Both);
108 
109             client.Close();
110 
111 }
112 
113         catch (Exception e){
114 
115             Console.WriteLine(e.ToString());}
116 
117     }
118 
119  
120 
121     private static void ConnectCallback(IAsyncResult ar)
122 
123     {
124 
125         try{
126 
127             // Retrieve the socket from the state object.
128 
129             Socket client = (Socket)ar.AsyncState;
130 
131  
132 
133             // Complete the connection.
134 
135             client.EndConnect(ar);
136 
137  
138 
139             Console.WriteLine("Socket connected to {0}",
140 
141                 client.RemoteEndPoint.ToString());
142 
143  
144 
145             // Signal that the connection has been made.
146 
147             connectDone.Set();
148 
149         }
150 
151         catch (Exception e){
152 
153             Console.WriteLine(e.ToString());}
154 
155     }
156 
157  
158 
159     private static void Receive(Socket client)
160 
161     {
162 
163         try{
164 
165             // Create the state object.
166 
167             StateObject state = new StateObject();
168 
169             state.workSocket = client;
170 
171  
172 
173             // Begin receiving the data from the remote device.
174 
175             client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
176 
177                 new AsyncCallback(ReceiveCallback), state);
178 
179         }
180 
181         catch (Exception e){
182 
183             Console.WriteLine(e.ToString());}
184 
185     }
186 
187  
188 
189     private static void ReceiveCallback(IAsyncResult ar)
190 
191     {
192 
193         try{
194 
195             // Retrieve the state object and the client socket
196 
197             // from the asynchronous state object.
198 
199             StateObject state = (StateObject)ar.AsyncState;
200 
201             Socket client = state.workSocket;
202 
203  
204 
205             // Read data from the remote device.
206 
207             int bytesRead = client.EndReceive(ar);
208 
209  
210 
211             if (bytesRead > 0){
212 
213                 // There might be more data, so store the data received so far.
214 
215                 state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
216 
217  
218 
219                 // Get the rest of the data.
220 
221                 client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
222 
223                     new AsyncCallback(ReceiveCallback), state);
224 
225             }
226 
227             else{
228 
229                 // All the data has arrived; put it in response.
230 
231                 if (state.sb.Length > 1)
232 
233                 {
234 
235                     response = state.sb.ToString();
236 
237                 }
238 
239                 // Signal that all bytes have been received.
240 
241                 receiveDone.Set();
242 
243             }
244 
245         }
246 
247         catch (Exception e){
248 
249             Console.WriteLine(e.ToString());}
250 
251     }
252 
253  
254 
255     private static void Send(Socket client, String data)
256 
257     {
258 
259         // Convert the string data to byte data using ASCII encoding.
260 
261         byte[] byteData = Encoding.ASCII.GetBytes(data);
262 
263  
264 
265         // Begin sending the data to the remote device.
266 
267         client.BeginSend(byteData, 0, byteData.Length, 0,
268 
269             new AsyncCallback(SendCallback), client);
270 
271     }
272 
273  
274 
275     private static void SendCallback(IAsyncResult ar)
276 
277     {
278 
279         try{
280 
281             // Retrieve the socket from the state object.
282 
283             Socket client = (Socket)ar.AsyncState;
284 
285  
286 
287             // Complete sending the data to the remote device.
288 
289             int bytesSent = client.EndSend(ar);
290 
291             Console.WriteLine("Sent {0} bytes to server.", bytesSent);
292 
293  
294 
295             // Signal that all bytes have been sent.
296 
297             sendDone.Set();
298 
299 }
300 
301         catch (Exception e){
302 
303             Console.WriteLine(e.ToString());}
304 
305     }
306 
307  
308 
309     public static int Main(String[] args)
310 
311     {
312 
313         StartClient();
314 
315         return 0;
316 
317     }
318 
319 }
View Code

服务器端Server:预定义结构体,用于异步委托之间的传递。同客户端的一致。不再赘述

  1 // State object for reading client data asynchronously
  2 
  3 public class AsynchronousSocketListener
  4 
  5 {
  6 
  7     // Thread signal.
  8 
  9     public static ManualResetEvent allDone = new ManualResetEvent(false);
 10 
 11     public AsynchronousSocketListener(){}
 12 
 13     public static void StartListening()
 14 
 15     {
 16 
 17         // Data buffer for incoming data.
 18 
 19         byte[] bytes = new Byte[1024];
 20 
 21         // Establish the local endpoint for the socket.
 22 
 23         // The DNS name of the computer
 24 
 25         // running the listener is "host.contoso.com".
 26 
 27  
 28 
 29         //IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
 30 
 31         IPHostEntry ipHostInfo = Dns.Resolve("127.0.0.1");
 32 
 33         IPAddress ipAddress = ipHostInfo.AddressList[0];
 34 
 35         IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
 36 
 37         // Create a TCP/IP socket.
 38 
 39         Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
 40 
 41         // Bind the socket to the local endpoint and listen for incoming connections.
 42 
 43         try{
 44 
 45             listener.Bind(localEndPoint);
 46 
 47             listener.Listen(100);
 48 
 49             while (true){
 50 
 51                 // Set the event to nonsignaled state.
 52 
 53                 allDone.Reset();
 54 
 55                 // Start an asynchronous socket to listen for connections.
 56 
 57                 Console.WriteLine("Waiting for a connection...");
 58 
 59                 listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
 60 
 61                 // Wait until a connection is made before continuing.
 62 
 63                 allDone.WaitOne();
 64 
 65             }
 66 
 67         }
 68 
 69         catch (Exception e){
 70 
 71             Console.WriteLine(e.ToString());}
 72 
 73         Console.WriteLine("
Press ENTER to continue...");
 74 
 75         Console.Read();
 76 
 77     }
 78 
 79     public static void AcceptCallback(IAsyncResult ar)
 80 
 81     {
 82 
 83         // Signal the main thread to continue.
 84 
 85         allDone.Set();
 86 
 87         // Get the socket that handles the client request.
 88 
 89         Socket listener = (Socket)ar.AsyncState;
 90 
 91         Socket handler = listener.EndAccept(ar);
 92 
 93         // Create the state object.
 94 
 95         StateObject state = new StateObject();
 96 
 97         state.workSocket = handler;
 98 
 99         handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,newAsyncCallback(ReadCallback), state);
100 
101     }
102 
103     public static void ReadCallback(IAsyncResult ar)
104 
105     {
106 
107         String content = String.Empty;
108 
109         // Retrieve the state object and the handler socket
110 
111         // from the asynchronous state object.
112 
113         StateObject state = (StateObject)ar.AsyncState;
114 
115         Socket handler = state.workSocket;
116 
117         // Read data from the client socket.
118 
119         int bytesRead = handler.EndReceive(ar);
120 
121         if (bytesRead > 0)
122 
123         {
124 
125             // There    might be more data, so store the data received so far.
126 
127             state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
128 
129             // Check for end-of-file tag. If it is not there, read
130 
131             // more data.
132 
133             content = state.sb.ToString();
134 
135             if (content.IndexOf("<EOF>") > -1){
136 
137                 // All the data has been read from the
138 
139                 // client. Display it on the console.
140 
141                 Console.WriteLine("Read {0} bytes from socket. 
 Data : {1}",
142 
143                 content.Length, content);
144 
145                 // Echo the data back to the client.
146 
147                 Send(handler, "Server return :" + content);
148 
149             }
150 
151             else{
152 
153                 // Not all data received. Get more.
154 
155                 handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
156 
157                 new AsyncCallback(ReadCallback), state);
158 
159             }
160 
161         }
162 
163     }
164 
165     private static void Send(Socket handler, String data){
166 
167         // Convert the string data to byte data using ASCII encoding.
168 
169         byte[] byteData = Encoding.ASCII.GetBytes(data);
170 
171         // Begin sending the data to the remote device.
172 
173         handler.BeginSend(byteData, 0, byteData.Length, 0,
174 
175         new AsyncCallback(SendCallback), handler);
176 
177     }
178 
179     private static void SendCallback(IAsyncResult ar)
180 
181     {
182 
183         try{
184 
185             // Retrieve the socket from the state object.
186 
187             Socket handler = (Socket)ar.AsyncState;
188 
189             // Complete sending the data to the remote device.
190 
191             int bytesSent = handler.EndSend(ar);
192 
193             Console.WriteLine("Sent {0} bytes to client.", bytesSent);
194 
195             handler.Shutdown(SocketShutdown.Both);
196 
197             handler.Close();
198 
199         }
200 
201         catch (Exception e){
202 
203             Console.WriteLine(e.ToString());
204 
205         }
206 
207     }
208 
209     public static int Main(String[] args)
210 
211     {
212 
213         StartListening();
214 
215         return 0;
216 
217     }
218 
219 }
View Code
原文地址:https://www.cnblogs.com/anyihen/p/12782109.html