SocketAsyncEventArgs 類別
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
代表非同步通訊端作業。
public ref class SocketAsyncEventArgs : EventArgs, IDisposable
public class SocketAsyncEventArgs : EventArgs, IDisposable
type SocketAsyncEventArgs = class
inherit EventArgs
interface IDisposable
Public Class SocketAsyncEventArgs
Inherits EventArgs
Implements IDisposable
- 繼承
- 實作
範例
下列程式代碼範例會實作使用 SocketAsyncEventArgs 類別之套接字伺服器的連接邏輯。 接受連線之後,從用戶端讀取的所有數據都會傳回給用戶端。 讀取和回顯用戶端模式會繼續,直到用戶端中斷連線為止。 這個範例所使用的 BufferManager 類別會顯示在 方法的程式代碼範例 SetBuffer(Byte[], Int32, Int32) 中。 此範例中使用的 SocketAsyncEventArgsPool 類別會顯示在建構函式的程式碼範例中 SocketAsyncEventArgs 。
// Implements the connection logic for the socket server.
// After accepting a connection, all data read from the client
// is sent back to the client. The read and echo back to the client pattern
// is continued until the client disconnects.
class Server
{
private int m_numConnections; // the maximum number of connections the sample is designed to handle simultaneously
private int m_receiveBufferSize;// buffer size to use for each socket I/O operation
BufferManager m_bufferManager; // represents a large reusable set of buffers for all socket operations
const int opsToPreAlloc = 2; // read, write (don't alloc buffer space for accepts)
Socket listenSocket; // the socket used to listen for incoming connection requests
// pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations
SocketAsyncEventArgsPool m_readWritePool;
int m_totalBytesRead; // counter of the total # bytes received by the server
int m_numConnectedSockets; // the total number of clients connected to the server
Semaphore m_maxNumberAcceptedClients;
// Create an uninitialized server instance.
// To start the server listening for connection requests
// call the Init method followed by Start method
//
// <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param>
// <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param>
public Server(int numConnections, int receiveBufferSize)
{
m_totalBytesRead = 0;
m_numConnectedSockets = 0;
m_numConnections = numConnections;
m_receiveBufferSize = receiveBufferSize;
// allocate buffers such that the maximum number of sockets can have one outstanding read and
//write posted to the socket simultaneously
m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc,
receiveBufferSize);
m_readWritePool = new SocketAsyncEventArgsPool(numConnections);
m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
}
// Initializes the server by preallocating reusable buffers and
// context objects. These objects do not need to be preallocated
// or reused, but it is done this way to illustrate how the API can
// easily be used to create reusable objects to increase server performance.
//
public void Init()
{
// Allocates one large byte buffer which all I/O operations use a piece of. This gaurds
// against memory fragmentation
m_bufferManager.InitBuffer();
// preallocate pool of SocketAsyncEventArgs objects
SocketAsyncEventArgs readWriteEventArg;
for (int i = 0; i < m_numConnections; i++)
{
//Pre-allocate a set of reusable SocketAsyncEventArgs
readWriteEventArg = new SocketAsyncEventArgs();
readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
// assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
m_bufferManager.SetBuffer(readWriteEventArg);
// add SocketAsyncEventArg to the pool
m_readWritePool.Push(readWriteEventArg);
}
}
// Starts the server such that it is listening for
// incoming connection requests.
//
// <param name="localEndPoint">The endpoint which the server will listening
// for connection requests on</param>
public void Start(IPEndPoint localEndPoint)
{
// create the socket which listens for incoming connections
listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(localEndPoint);
// start the server with a listen backlog of 100 connections
listenSocket.Listen(100);
// post accepts on the listening socket
SocketAsyncEventArgs acceptEventArg = new SocketAsyncEventArgs();
acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
StartAccept(acceptEventArg);
//Console.WriteLine("{0} connected sockets with one outstanding receive posted to each....press any key", m_outstandingReadCount);
Console.WriteLine("Press any key to terminate the server process....");
Console.ReadKey();
}
// Begins an operation to accept a connection request from the client
//
// <param name="acceptEventArg">The context object to use when issuing
// the accept operation on the server's listening socket</param>
public void StartAccept(SocketAsyncEventArgs acceptEventArg)
{
// loop while the method completes synchronously
bool willRaiseEvent = false;
while (!willRaiseEvent)
{
m_maxNumberAcceptedClients.WaitOne();
// socket must be cleared since the context object is being reused
acceptEventArg.AcceptSocket = null;
willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
if (!willRaiseEvent)
{
ProcessAccept(acceptEventArg);
}
}
}
// This method is the callback method associated with Socket.AcceptAsync
// operations and is invoked when an accept operation is complete
//
void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
{
ProcessAccept(e);
// Accept the next connection request
StartAccept(e);
}
private void ProcessAccept(SocketAsyncEventArgs e)
{
Interlocked.Increment(ref m_numConnectedSockets);
Console.WriteLine("Client connection accepted. There are {0} clients connected to the server",
m_numConnectedSockets);
// Get the socket for the accepted client connection and put it into the
//ReadEventArg object user token
SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
readEventArgs.UserToken = e.AcceptSocket;
// As soon as the client is connected, post a receive to the connection
bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
if (!willRaiseEvent)
{
ProcessReceive(readEventArgs);
}
}
// This method is called whenever a receive or send operation is completed on a socket
//
// <param name="e">SocketAsyncEventArg associated with the completed receive operation</param>
void IO_Completed(object sender, SocketAsyncEventArgs e)
{
// determine which type of operation just completed and call the associated handler
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
ProcessSend(e);
break;
default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
}
}
// This method is invoked when an asynchronous receive operation completes.
// If the remote host closed the connection, then the socket is closed.
// If data was received then the data is echoed back to the client.
//
private void ProcessReceive(SocketAsyncEventArgs e)
{
// check if the remote host closed the connection
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
//increment the count of the total bytes receive by the server
Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred);
Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead);
//echo the data received back to the client
e.SetBuffer(e.Offset, e.BytesTransferred);
Socket socket = (Socket)e.UserToken;
bool willRaiseEvent = socket.SendAsync(e);
if (!willRaiseEvent)
{
ProcessSend(e);
}
}
else
{
CloseClientSocket(e);
}
}
// This method is invoked when an asynchronous send operation completes.
// The method issues another receive on the socket to read any additional
// data sent from the client
//
// <param name="e"></param>
private void ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// done echoing data back to the client
Socket socket = (Socket)e.UserToken;
// read the next block of data send from the client
bool willRaiseEvent = socket.ReceiveAsync(e);
if (!willRaiseEvent)
{
ProcessReceive(e);
}
}
else
{
CloseClientSocket(e);
}
}
private void CloseClientSocket(SocketAsyncEventArgs e)
{
Socket socket = (Socket)e.UserToken;
// close the socket associated with the client
try
{
socket.Shutdown(SocketShutdown.Send);
}
// throws if client process has already closed
catch (Exception) { }
socket.Close();
// decrement the counter keeping track of the total number of clients connected to the server
Interlocked.Decrement(ref m_numConnectedSockets);
// Free the SocketAsyncEventArg so they can be reused by another client
m_readWritePool.Push(e);
m_maxNumberAcceptedClients.Release();
Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets);
}
}
備註
類別 SocketAsyncEventArgs 是類別的一組增強功能 System.Net.Sockets.Socket 之一部分,可提供特殊高效能套接字應用程式可使用的替代異步模式。 這個類別特別針對需要高效能的網路伺服器應用程式所設計。 例如,當接收大量數據) 時,應用程式可以單獨使用增強的異步模式,或只能在目標作用中區域使用 (。
這些增強功能的主要功能是在大量的非同步通訊端 I/O 期間,避免重複配置和同步處理物件。 類別目前實作的 System.Net.Sockets.Socket Begin/End 設計模式需要 System.IAsyncResult 為每個異步套接字作業配置 物件。
在新的 System.Net.Sockets.Socket 類別增強功能中,異步套接字作業是由應用程式所配置和維護的可重複使用 SocketAsyncEventArgs 物件所描述。 高效能通訊端應用程式最知道必須維持的重疊通訊端作業量。 應用程式可以視需要建立許多 SocketAsyncEventArgs 物件。 例如,如果伺服器應用程式必須隨時有15個套接字接受作業,以支援連入用戶端連線速率,它可以針對該目的配置15個可重複使用 SocketAsyncEventArgs 的物件。
以這個類別執行非同步通訊端作業的模式,包含下列步驟:
配置新 SocketAsyncEventArgs 內容物件,或從應用程式集區取得一個可用的內容物件。
將內容物件上的屬性設定為即將執行的作業, (完成回呼方法、數據緩衝區、緩衝區中的位移,以及要傳送的數據量上限,例如) 。
呼叫適當的通訊端方法 (xxxAsync) 來啟始非同步作業。
如果異步套接字方法 (xxxAsync) 傳回 true,請在回呼中查詢內容屬性以取得完成狀態。
如果異步套接字方法 (xxxAsync) 傳回 false,則作業會以同步方式完成。 可以查詢內容屬性以取得作業結果。
重複使用內容進行另一個作業、將它放入集區,或是將它捨棄。
新異步套接字作業內容物件的存留期是由應用程式程式代碼和異步 I/O 參考的參考所決定。 應用程式不需要在送出作為其中一個非同步通訊端作業方法的參數之後,保留對非同步通訊端作業內容物件的參考。 在完成回呼傳回之前,它會一直被參考。 不過,應用程式可讓應用程式保留內容的參考,以便在未來的異步套接字作業中重複使用它。
建構函式
SocketAsyncEventArgs() |
建立空的 SocketAsyncEventArgs 執行個體。 |
SocketAsyncEventArgs(Boolean) |
初始化 SocketAsyncEventArgs。 |
屬性
AcceptSocket |
取得或設定要使用的通訊端,或是已建立並且使用非同步通訊端方法接受連線的通訊端。 |
Buffer |
取得要和非同步通訊端方法一起使用的資料緩衝區。 |
BufferList |
取得或設定要和非同步通訊端方法一起使用的資料緩衝區之陣列。 |
BytesTransferred |
取得通訊端作業中所傳輸的位元組數目。 |
ConnectByNameError |
取得使用 DnsEndPoint 時發生連接失敗的例外狀況 (Exception)。 |
ConnectSocket |
Socket 方法成功完成後已建立和連接的 ConnectAsync 物件。 |
Count |
取得非同步作業中要傳送或接收的資料量上限 (以位元組為單位)。 |
DisconnectReuseSocket |
取得或設定值,指定在中斷連接作業後是否可以重複使用通訊端。 |
LastOperation |
取得最近使用這個內容物件執行的通訊端作業類型。 |
MemoryBuffer |
取得使用非同步通訊端方法作為緩衝區使用的記憶體區域。 |
Offset |
取得 Buffer 屬性所參考之資料緩衝區中的位移 (以位元組為單位)。 |
ReceiveMessageFromPacketInfo |
取得接收之封包的 IP 位址和介面。 |
RemoteEndPoint |
取得或設定非同步作業的遠端 IP 端點。 |
SendPacketsElements |
取得或設定要為 SendPacketsAsync(SocketAsyncEventArgs) 方法所使用的非同步作業傳送的緩衝區陣列。 |
SendPacketsFlags |
取得或設定 TransmitFileOptions 方法所使用之非同步作業的 SendPacketsAsync(SocketAsyncEventArgs) 值的位元組合。 |
SendPacketsSendSize |
取得或設定傳送作業中所使用的資料區塊大小 (以位元組為單位)。 |
SocketClientAccessPolicyProtocol |
已淘汰.
取得或設定要用來下載通訊端用戶端存取原則檔的通訊協定。 |
SocketError |
取得或設定非同步通訊端作業的結果。 |
SocketFlags |
取得非同步通訊端作業的結果,或設定非同步作業的行為。 |
UserToken |
取得或設定與這個非同步通訊端作業相關聯的使用者或應用程式物件。 |
方法
Dispose() |
釋放 SocketAsyncEventArgs 執行個體所使用的 Unmanaged 資源,並選擇性地處置 Managed 資源。 |
Equals(Object) |
判斷指定的物件是否等於目前的物件。 (繼承來源 Object) |
Finalize() |
釋放 SocketAsyncEventArgs 類別所使用的資源。 |
GetHashCode() |
做為預設雜湊函式。 (繼承來源 Object) |
GetType() |
取得目前執行個體的 Type。 (繼承來源 Object) |
MemberwiseClone() |
建立目前 Object 的淺層複製。 (繼承來源 Object) |
OnCompleted(SocketAsyncEventArgs) |
代表在非同步作業完成時所呼叫的方法。 |
SetBuffer(Byte[], Int32, Int32) |
設定要和非同步通訊端方法一起使用的資料緩衝區。 |
SetBuffer(Int32, Int32) |
設定要和非同步通訊端方法一起使用的資料緩衝區。 |
SetBuffer(Memory<Byte>) |
設定使用非同步通訊端方法作為緩衝區使用的記憶體區域。 |
ToString() |
傳回代表目前物件的字串。 (繼承來源 Object) |
事件
Completed |
用來完成非同步作業的事件。 |
適用於
另請參閱
- IAsyncResult
- Socket
- AcceptAsync(SocketAsyncEventArgs)
- ConnectAsync(SocketAsyncEventArgs)
- DisconnectAsync(SocketAsyncEventArgs)
- ReceiveAsync(SocketAsyncEventArgs)
- ReceiveFromAsync(SocketAsyncEventArgs)
- ReceiveMessageFromAsync(SocketAsyncEventArgs)
- SendAsync(SocketAsyncEventArgs)
- SendPacketsAsync(SocketAsyncEventArgs)
- SendToAsync(SocketAsyncEventArgs)
- 以 .NET Framework 進行網路程式設計
- 以 .NET Framework 進行網路追蹤
- 3.5 版中的通訊端效能增強功能