基于c#的socket编程的tcp异步实现_第1页
基于c#的socket编程的tcp异步实现_第2页
基于c#的socket编程的tcp异步实现_第3页
基于c#的socket编程的tcp异步实现_第4页
基于c#的socket编程的tcp异步实现_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

基于基于 C#的的 socket 编程的编程的 TCP 异步实现异步实现 一、摘要一、摘要 本篇博文阐述基于 TCP 通信协议的异步实现。 二、实验平台二、实验平台 Visual Studio 2010 三、异步通信实现原理及常用方法三、异步通信实现原理及常用方法 3.1 建立连接建立连接 在同步模式中,在服务器上使用 Accept 方法接入连接请求,而在客户端 则使用 Connect 方法来连接服务器。相对地,在异步模式下,服务器可以使用 BeginAccept 方法和 EndAccept 方法来完成连接到客户端的任务,在客户端 则通过 BeginConnect 方法和 EndConnect 方法来实现与服务器的连接。 BeginAccept 在异步方式下传入的连接尝试,它允许其他动作而不必等待 连接建立才继续执行后面程序。在调用 BeginAccept 之前,必须使用 Listen 方法来侦听是否有连接请求,BeginAccept 的函数原型为: BeginAccept(AsyncCallback AsyncCallback, Ojbect state) 参数: AsyncCallBack:代表回调函数 state:表示状态信息,必须保证 state 中包含 socket 的句柄 使用 BeginAccept 的基本流程是: (1)创建本地终节点,并新建套接字与本地终节点进行绑定; (2)在端口上侦听是否有新的连接请求; (3)请求开始接入新的连接,传入 Socket 的实例或者 StateOjbect 的实例。 参考代码: /定义 IP 地址 IPAddress local = IPAddress.Parse(“127.0,0,1“); IPEndPoint iep = new IPEndPoint(local,13000); /创建服务器的 socket 对象 Socket server = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); server.Bind(iep); server.Listen(20); server.BeginAccecpt(new AsyncCallback(Accept),server); 当 BeginAccept()方法调用结束后,一旦新的连接发生,将调用回调函数, 而该回调函数必须包括用来结束接入连接操作的 EndAccept()方法。 该方法参数列表为 Socket EndAccept(IAsyncResult iar) 下面为回调函数的实例: void Accept(IAsyncResult iar) /还原传入的原始套接字 Socket MyServer = (Socket)iar.AsyncState; /在原始套接字上调用 EndAccept 方法,返回新的套接字 Socket service = MyServer.EndAccept(iar); 至此,服务器端已经准备好了。客户端应通过 BeginConnect 方法和 EndConnect 来远程连接主机。在调用 BeginConnect 方法时必须注册相应 的回调函数并且至少传递一个 Socket 的实例给 state 参数,以保证 EndConnect 方法中能使用原始的套接字。下面是一段是 BeginConnect 的 调用: Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp) IPAddress ip=IPAddress.Parse(““); IPEndPoint iep=new IPEndPoint(ip,13000); socket.BeginConnect(iep, new AsyncCallback(Connect),socket); EndConnect 是一种阻塞方法,用于完成 BeginConnect 方法的异步连 接诶远程主机的请求。在注册了回调函数后必须接收 BeginConnect 方法返回 的 IASynccReuslt 作为参数。下面为代码演示: void Connect(IAsyncResult iar) Socket client=(Socket)iar.AsyncState; try client.EndConnect(iar); catch (Exception e) Console.WriteLine(e.ToString(); finally 除了采用上述方法建立连接之后,也可以采用 TcpListener 类里面的方法 进行连接建立。下面是服务器端对关于 TcpListener 类使用 BeginAccetpTcpClient 方法处理一个传入的连接尝试。以下是使用 BeginAccetpTcpClient 方法和 EndAccetpTcpClient 方法的代码: public static void DoBeginAccept(TcpListener listner) /开始从客户端监听连接 Console.WriteLine(“Waitting for a connection“); /接收连接 /开始准备接入新的连接,一旦有新连接尝试则调用回调函数 DoAcceptTcpCliet listner.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpCliet), listner); /处理客户端的连接 public static void DoAcceptTcpCliet(IAsyncResult iar) /还原原始的 TcpListner 对象 TcpListener listener = (TcpListener)iar.AsyncState; /完成连接的动作,并返回新的 TcpClient TcpClient client = listener.EndAcceptTcpClient(iar); Console.WriteLine(“连接成功“); 代码的处理逻辑为: (1)调用 BeginAccetpTcpClient 方法开开始连接新的连接,当连接视图发生 时,回调函数被调用以完成连接操作; (2)上面 DoAcceptTcpCliet 方法通过 AsyncState 属性获得由 BeginAcceptTcpClient 传入的 listner 实例; (3)在得到 listener 对象后,用它调用 EndAcceptTcpClient 方法,该方法返 回新的包含客户端信息的 TcpClient。 BeginConnect 方法和 EndConnect 方法可用于客户端尝试建立与服务 端的连接,这里和第一种方法并无区别。下面看实例: public void doBeginConnect(IAsyncResult iar) Socket client=(Socket)iar.AsyncState; /开始与远程主机进行连接 client.BeginConnect(serverIP0,13000,requestCallBack,client); Console.WriteLine(“开始与服务器进行连接“); private void requestCallBack(IAsyncResult iar) try /还原原始的 TcpClient 对象 TcpClient client=(TcpClient)iar.AsyncState; / client.EndConnect(iar); Console.WriteLine(“与服务器0连接成功 “,client.Client.RemoteEndPoint); catch(Exception e) Console.WriteLine(e.ToString(); finally 以上是建立连接的两种方法。可根据需要选择使用。 3.2 发送与接受数据发送与接受数据 在建立了套接字的连接后,就可以服务器端和客户端之间进行数据通信了。 异步套接字用 BeginSend 和 EndSend 方法来负责数据的发送。注意在调用 BeginSend 方法前要确保双方都已经建立连接,否则会出异常。下面演示代码: private static void Send(Socket handler, String data) / Convert the string data to byte data using ASCII encoding. byte byteData = Encoding.ASCII.GetBytes(data); / Begin sending the data to the remote device. handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler); private static void SendCallback(IAsyncResult ar) try / Retrieve the socket from the state object. Socket handler = (Socket)ar.AsyncState; / Complete sending the data to the remote device. int bytesSent = handler.EndSend(ar); Console.WriteLine(“Sent 0 bytes to client.“, bytesSent); handler.Shutdown(SocketShutdown.Both); handler.Close(); catch (Exception e) Console.WriteLine(e.ToString(); 接收数据是通过 BeginReceive 和 EndReceive 方法: private static void Receive(Socket client) try / Create the state object. StateObject state = new StateObject(); state.workSocket = client; / Begin receiving the data from the remote device. client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); catch (Exception e) Console.WriteLine(e.ToString(); private static void ReceiveCallback(IAsyncResult ar) try / Retrieve the state object and the client socket / from the asynchronous state object. StateObject state = (StateObject)ar.AsyncState; Socket client = state.workSocket; / Read data from the remote device. int bytesRead = client.EndReceive(ar); if (bytesRead 0) / There might be more data, so store the data received so far. state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead); / Get the rest of the data. client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); else / All the data has arrived; put it in response. if (state.sb.Length 1) response = state.sb.ToString(); / Signal that all bytes have been received. receiveDone.Set(); catch (Exception e) Console.WriteLine(e.ToString(); 上述代码的处理逻辑为: (1)首先处理连接的回调函数里得到的通讯套接字 client,接着开始接收数据; (2)当数据发送到缓冲区中,BeginReceive 方法试图从 buffer 数组中读取长 度为 buffer.length 的数据块,并返回接收到的数据量bytesRead。最后接收 并打印数据。 除了上述方法外,还可以使用基于 NetworkStream 相关的异步发送和接 收方法,下面是基于 NetworkStream 相关的异步发送和接收方法的使用介绍。 NetworkStream 使用 BeginRead 和 EndRead 方法进行读操作,使用 BeginWreite 和 EndWrete 方法进行写操作,下面看实例: static void DataHandle(TcpClient client) TcpClient tcpClient = client; /使用 TcpClient 的 GetStream 方法获取网络流 NetworkStream ns = tcpClient.GetStream(); /检查网络流是否可读 if(ns.CanRead) /定义缓冲区 byte read = new byte1024; ns.BeginRead(read,0,read.Length,new AsyncCallback(myReadCallBack),ns); else Console.WriteLine(“无法从网络中读取流数据“); public static void myReadCallBack(IAsyncResult iar) NetworkStream ns = (NetworkStream)iar.AsyncState; byte read = new byte1024; String data = “; int recv; recv = ns.EndRead(iar); data = String.Concat(data, Encoding.ASCII.GetString(read, 0, recv); /接收到的消息长度可能大于缓冲区总大小,反复循环直到读完为止 while (ns.DataAvailable) ns.BeginRead(read, 0, read.Length, new AsyncCallback(myReadCallBack), ns); /打印 Console.WriteLine(“您收到的信息是“ + data); 3.3 程序阻塞与异步中的同步问题程序阻塞与异步中的同步问题 .Net 里提供了 EventWaitHandle 类来表示一个线程的同步事件。 EventWaitHandle 即事件等待句柄,他允许线程通过操作系统互发信号和等 待彼此的信号来达到线程同步的目的。这个类有 2 个子类,分别为 AutoRestEevnt(自动重置)和 ManualRestEvent(手动重置)。下面是线程同 步的几个方法: (1)Rset 方法:将事件状态设为非终止状态,导致线程阻塞。这里的线程阻塞 是指允许其他需要等待的线程进行阻塞即让含 WaitOne()方法的线程阻塞; (2)Set 方法:将事件状态设为终止状态,允许一个或多个等待线程继续。该方 法发送一个信号给操作系统,让处于等待的某个线程从阻塞状态转换为继续运 行,即 WaitOne 方法的线程不在阻塞; (3)WaitOne 方法:阻塞当前线程,直到当前的等待句柄收到信号。此方法将 一直使本线程处于阻塞状态直到收到信号为止,即当其他非阻塞进程调用 set 方法时可以继续执行。 public static void StartListening() / Data buffer for incoming data. byte bytes = new Byte1024; / Establish the local endpoint for the socket. / The DNS name of the computer / running the listener is ““. /IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName(); /IPAddress ipAddress = ipHostInfo.AddressList0; IPAddress ipAddress = IPAddress.Parse(““); IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); / Create a TCP/IP socket. Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); / Bind the socket to the local /endpoint and listen for incoming connections. try listener.Bind(localEndPoint); listener.Listen(100); while (true) / Set the event to nonsignaled state. allDone.Reset(); / Start an asynchronous socket to listen for connections. Console.WriteLine(“Waiting for a connection.“); listener.BeginAccept(new AsyncCallback(AcceptCallback),listener); / Wait until a connection is made before continuing. allDone.WaitOne(); catch (Exception e) Console.WriteLine(e.ToString(); Console.WriteLine(“nPress ENTER to continue.“); Console.Read(); 上述代码的逻辑为: (1)试用了 ManualRestEvent 对象创建一个等待句柄,在调用 BeginAccept 方法前使用 Rest 方法允许其他线程阻塞; (2)为了防止在连接完成之前对套接字进行读写操作,务必要在 BeginAccept 方法后调用 WaitOne 来让线程进入阻塞状态。 当有连接接入后系统会自动调用会调用回调函数,所以当代码执行到回调 函数时说明连接已经成功,并在函数的第一句就调用 Set 方法让处于等待的线 程可以继续执行。 四、实例四、实例 下面是一个实例,客户端请求连接,服务器端侦听端口,当连接建立之后, 服务器发送字符串给客户端,客户端收到后并回发给服务器端。 服务器端代码: using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; / State object for reading client data asynchronously public class StateObject / Client socket. public Socket workSocket = null; / Size of receive buffer. public const int BufferSize = 1024; / Receive buffer. public byte buffer = new byteBufferSize; / Received data string. public StringBuilder sb = new StringBuilder(); public class AsynchronousSocketListener / Thread signal. public static ManualResetEvent allDone = new ManualResetEvent(false); public AsynchronousSocketListener() public static void StartListening() / Data buffer for incoming data. byte bytes = new Byte1024; / Establish the local endpoint for the socket. / The DNS name of the computer / running the listener is ““. /IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName(); /IPAddress ipAddress = ipHostInfo.AddressList0; IPAddress ipAddress = IPAddress.Parse(““); IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); / Create a TCP/IP socket. Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); / Bind the socket to the local /endpoint and listen for incoming connections. try listener.Bind(localEndPoint); listener.Listen(100); while (true) / Set the event to nonsignaled state. allDone.Reset(); / Start an asynchronous socket to listen for connections. Console.WriteLine(“Waiting for a connection.“); listener.BeginAccept(new AsyncCallback(AcceptCallback),listener); / Wait until a connection is made before continuing. allDone.WaitOne(); catch (Exception e) Console.WriteLine(e.ToString(); Console.WriteLine(“nPress ENTER to continue.“); Console.Read(); public static void AcceptCallback(IAsyncResult ar) / Signal the main thread to continue. allDone.Set(); / Get the socket that handles the client request. Socket listener = (Socket)ar.AsyncState; Socket handler = listener.EndAccept(ar); / Create the state object. StateObject state = new StateObject(); state.workSocket = handler; handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); public static void ReadCallback(IAsyncResult ar) String content = String.Empty; / Retrieve the state object and the handler socket / from the asynchronous state object. StateObject state = (StateObject)ar.AsyncState; Socket handler = state.workSocket; / Read data from the client socket. int bytesRead = handler.EndReceive(ar); if (bytesRead 0) / There might be more data, so store the data received so far. state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead); / Check for end-of-file tag. If it is not there, read / more data. content = state.sb.ToString(); if (content.IndexOf(“) -1) / All the data has been read from the / client. Display it on the console. Console.WriteLine(“Read 0 bytes from socket. n Data : 1“, content.Length, content); / Echo the data back to the client. Send(handler, content); else / Not all data received. Get more. handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); private static void Send(Socket handler, String data) / Convert the string data to byte data using ASCII encoding. byte byteData = Encoding.ASCII.GetBytes(data); / Begin sending the data to the remote device. handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler); private static void SendCallback(IAsyncResult ar) try / Retrieve the socket from the state object. Socket handler = (Socket)ar.AsyncState; / Complete sending the data to the remote device. int bytesSent = handler.EndSend(ar); Console.WriteLine(“Sent 0 bytes to client.“, bytesSent); handler.Shutdown(SocketShutdown.Both); handler.Close(); catch (Exception e) Console.WriteLine(e.ToString(); public static int Main(String args) StartListening(); return 0; 客户端代码: using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Text; / State object for receiving data from remote device. public class StateObject / Client socket. public Socket workSocket = null; / Size of receive buffer. public const int BufferSize = 256; / Receive buffer. public byte buffer = new byteBufferSize; / Received data string. public StringBuilder sb = new StringBuilder(); public class AsynchronousClient / The port number for the remote device. private const int port = 11000; / ManualResetEvent instances signal completion. private static ManualResetEvent connectDone = new ManualResetEvent(false); private static ManualResetEvent sendDone = new ManualResetEvent(false); private static ManualResetEvent receiveDone = new ManualResetEvent(false); / The response from the remote device. private static String response = String.Empty; private static void StartClient() / Connect to a remote device. try / Establish the remote endpoint for the socket. / The name of the / remote device is ““. /IPHostEntry ipHostInfo = Dns.Resolve(“user“); /IPAddress ipAddress = ipHostInfo.AddressList0; IPAddress ipAddress = IPAddress.Parse(““); IPEndPoint remoteEP = new IPEndPoint(ipAddress, port); / Create a TCP/IP socket. Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); / Connect to the remote endpoint. client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client); connectDone.WaitOne(); / Send test data to the remote device. Send(client, “This is a test“); sendDone.WaitOne(); / Receive the response from the remote device. Receive(client); receiveDone.WaitOne(); / Write the response to the console. Console.WriteLine(“Response received : 0“, response); / Release the socket. client.Shutdown(SocketShutdown.Both); client.Close(); Console.ReadLine(); catch (Exception e) Console.WriteLine(e.ToString(); private static void ConnectCallback(IAsyncResult ar) try / Retrieve the socket from the state object. Socket client = (Socket)ar.AsyncState; / Complete the connection. client.EndConnect(ar); Console.WriteLine(“Socket connected to 0“, client.RemoteEndPoint.ToString(); / Signal that the connection has been made. connectDone.Set(); catch (Exception e) Console.WriteLine(e.ToString(); private static void Receive(Socket client) try / Create the state object. StateObject state = new StateObject(); state.workSocket = client; / Begin receiving the data from the remote device. client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论