读书人

Net.Socket怎么实现异步

发布时间: 2011-12-23 23:32:01 作者: rapoo

Net.Socket如何实现异步?
在把一个VB6下的程序向.net转,以前是用winsock控件做的,本身就是异步的。
多线程的,一次设置若干个winsock同时开启,然后异步的接收数据。
转到.net下就发现问题了,网上找的例子都是单线程的,而且是同步的,就是开启一个socket就在同一个过程中必须要结束他,必须等他传完才可以继续下一个,中间的过程似乎都被socket类托管了,没办法插手。没有类似于winsock控件的onDataArrive方法这个的确比较郁闷。

我想.Net不会这么弱的,肯定还是我弱,请高手赐教了。

[解决办法]
Begin下的方法全是异步
[解决办法]
异步服务器套接字使用 .NET Framework 异步编程模型处理网络服务请求。Socket 类遵循标准 .NET Framework 异步命名模式;例如,同步 Accept 方法对应异步 BeginAccept 和 EndAccept 方法。

异步服务器套接字需要一个开始接受网络连接请求的方法,一个处理连接请求并开始接收网络数据的回调方法以及一个结束接收数据的回调方法。本节将进一步讨论所有这些方法。

在下面的示例中,为开始接受网络连接请求,方法 StartListening 初始化 Socket,然后使用 BeginAccept 方法开始接受新连接。当套接字上接收到新连接请求时,将调用接受回调方法。它负责获取将处理连接的 Socket 实例,并将 Socket 提交给将处理请求的线程。接受回调方法实现 AsyncCallback 委托;它返回 void,并带一个 IAsyncResult 类型的参数。下面的示例是接受回调方法的外壳程序。

[Visual Basic]
Sub acceptCallback(ar As IAsyncResult)
' Add the callback code here.
End Sub 'acceptCallback


BeginAccept 方法带两个参数:指向接受回调方法的 AsyncCallback 委托和一个用于将状态信息传递给回调方法的对象。在下面的示例中,侦听 Socket 通过状态参数传递给回调方法。本示例创建一个 AsyncCallback 委托并开始接受网络连接。

[Visual Basic]
listener.BeginAccept( _
New AsyncCallback(SocketListener.acceptCallback),_
listener)


异步套接字使用系统线程池中的线程处理传入的连接。一个线程负责接受连接,另一线程用于处理每个传入的连接,还有一个线程负责接收连接数据。这些线程可以是同一个线程,具体取决于线程池所分配的线程。在下面的示例中,System.Threading.ManualResetEvent 类挂起主线程的执行并在执行可以继续时发出信号。

下面的示例显示在本地计算机上创建异步 TCP/IP 套接字并开始接受连接的异步方法。它假定以下内容:存在一个名为 allDone 的全局 ManualResetEvent,该方法是一个名为 SocketListener 的类的成员,以及定义了一个名为 acceptCallback 的回调方法。

[Visual Basic]
Public Sub StartListening()
Dim ipHostInfo As IPHostEntry = Dns.Resolve(Dns.GetHostName())
Dim localEP = New IPEndPoint(ipHostInfo.AddressList(0), 11000)

Console.WriteLine( "Local address and port : {0} ", localEP.ToString())

Dim listener As New Socket(localEP.Address.AddressFamily, _
SocketType.Stream, ProtocolType.Tcp)

Try
listener.Bind(localEP)
s.Listen(10)

While True
allDone.Reset()

Console.WriteLine( "Waiting for a connection... ")
listener.BeginAccept(New _
AsyncCallback(SocketListener.acceptCallback), _
listener)

allDone.WaitOne()
End While
Catch e As Exception
Console.WriteLine(e.ToString())
End Try
Console.WriteLine( "Closing the listener... ")
End Sub 'StartListening


接受回调方法(即前例中的 acceptCallback)负责向主应用程序发出信号,让它继续执行处理、建立与客户端的连接并开始异步读取客户端数据。下面的示例是 acceptCallback 方法实现的第一部分。该方法的此节向主应用程序线程发出信号,让它继续处理并建立与客户端的连接。它采用一个名为 allDone 的全局 ManualResetEvent。

[Visual Basic]
Public Sub acceptCallback(ar As IAsyncResult)
allDone.Set()

Dim listener As Socket = CType(ar.AsyncState, Socket)
Dim handler As Socket = listener.EndAccept(ar)

' Additional code to read data goes here.
End Sub 'acceptCallback


从客户端套接字读取数据需要一个在异步调用之间传递值的状态对象。下面的示例实现一个用于从远程客户端接收字符串的状态对象。它包含以下各项的字段:客户端套接字,用于接收数据的数据缓冲区,以及用于创建客户端发送的数据字符串的 StringBuilder。将这些字段放在该状态对象中,使这些字段的值在多个调用之间得以保留,以便从客户端套接字读取数据。

[Visual Basic]
Public Class StateObject
Public workSocket As Socket = Nothing
Public BufferSize As Integer = 1024
Public buffer(BufferSize) As Byte
Public sb As New StringBuilder()
End Class 'StateObject


开始从客户端套接字接收数据的 acceptCallback 方法的此节首先初始化 StateObject 类的一个实例,然后调用 BeginReceive 方法以开始从客户端套接字异步读取数据。


下面的示例显示了完整的 acceptCallback 方法。它假定以下内容:存在一个名为 allDone 的 ManualResetEvent,定义了 StateObject 类,以及在名为 SocketListener 的类中定义了 readCallback 方法。

[Visual Basic]
Public Shared Sub acceptCallback(ar As IAsyncResult)
' Get the socket that handles the client request.
Dim listener As Socket = CType(ar.AsyncState, Socket)
Dim handler As Socket = listener.EndAccept(ar)

' Signal the main thread to continue.
allDone.Set()

' Create the state object.
Dim state As New StateObject()
state.workSocket = handler
handler.BeginReceive(state.buffer, 0, state.BufferSize, 0, _
AddressOf AsynchronousSocketListener.readCallback, state)
End Sub 'acceptCallback


需要为异步套接字服务器实现的 final 方法是返回客户端发送的数据的读取回调方法。与接受回调方法一样,读取回调方法也是一个 AsyncCallback 委托。该方法将来自客户端套接字的一个或多个字节读入数据缓冲区,然后再次调用 BeginReceive 方法,直到客户端发送的数据完成为止。从客户端读取整个消息后,在控制台上显示字符串,并关闭处理与客户端的连接的服务器套接字。

下面的示例实现 readCallback 方法。它假定定义了 StateObject 类。

[Visual Basic]
Public Shared Sub readCallback(ar As IAsyncResult)
Dim state As StateObject = CType(ar.AsyncState, StateObject)
Dim handler As Socket = state.workSocket

' Read data from the client socket.
Dim read As Integer = handler.EndReceive(ar)

' Data was read from the client socket.
If read > 0 Then
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, read))
handler.BeginReceive(state.buffer, 0, state.BufferSize, 0, _
AddressOf readCallback, state)
Else
If state.sb.Length > 1 Then
' All the data has been read from the client;
' display it on the console.
Dim content As String = state.sb.ToString()
Console.WriteLine( "Read {0} bytes from socket. " + _
ControlChars.Cr + " Data : {1} ", content.Length, content)
End If
End If
End Sub 'readCallback

读书人网 >VB Dotnet

热点推荐