本文参考了http://www.codeproject.com/KB/IP/socketasynceventargssampl.aspx
作了一些修改
在.NET 2.0 SP1上可以使用SocketAsyncEventArgs类,本文的代码就是用Microsoft Visual Studio .NET 2005编写的。
Code
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace SocketAsyncClient
{
/**//// <summary>
/// socket客户端
/// 异步实现
/// </summary>
public sealed class SocketClient : IDisposable
{
/**//// <summary>
/// Constants for socket operations.
/// </summary>
private const Int32 ReceiveOperation = 1, SendOperation = 0;
/**//// <summary>
/// The socket used to send/receive messages.
/// </summary>
private Socket clientSocket;
/**//// <summary>
/// Flag for connected socket.
/// </summary>
private Boolean connected = false;
public Boolean Connected
{
get { return connected; }
}
/**//// <summary>
/// Listener endpoint.
/// </summary>
private IPEndPoint hostEndPoint;
/**//// <summary>
/// Signals a connection.
/// </summary>
private AutoResetEvent autoConnectEvent = new AutoResetEvent(false);
// private static AutoResetEvent autoConnectEvent = new AutoResetEvent(false);
/**//// <summary>
/// Signals the send/receive operation.
/// </summary>
// private static AutoResetEvent[] autoSendReceiveEvents = new AutoResetEvent[]
private AutoResetEvent[] autoSendReceiveEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};
/**//// <summary>
/// Create an uninitialized client instance.
/// To start the send/receive processing
/// call the Connect method followed by SendReceive method.
/// </summary>
/// <param name="hostName">Name of the host where the listener is running.</param>
/// <param name="port">Number of the TCP port from the listener.</param>
public SocketClient(String hostName, Int32 port)
{
// Get host related information.
IPHostEntry host = Dns.GetHostEntry(hostName);
// Addres of the host.
IPAddress[] addressList = host.AddressList;
// Instantiates the endpoint and socket.
this.hostEndPoint = new IPEndPoint(addressList[addressList.Length - 1], port);
this.clientSocket = new Socket(this.hostEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
/**//// <summary>
/// Connect to the host.
/// </summary>
/// <returns>True if connection has succeded, else false.</returns>
public void Connect()
{
SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs();
connectArgs.UserToken = this.clientSocket;
connectArgs.RemoteEndPoint = this.hostEndPoint;
connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnect);
clientSocket.ConnectAsync(connectArgs);
autoConnectEvent.WaitOne();
SocketError errorCode = connectArgs.SocketError;
if (errorCode != SocketError.Success)
{
throw new SocketException((Int32)errorCode);
}
}
/**//// <summary>
/// Disconnect from the host.
/// </summary>
public void Disconnect()
{
clientSocket.Disconnect(false);
}
private void OnConnect(object sender, SocketAsyncEventArgs e)
{
// Signals the end of connection.
autoConnectEvent.Set();
// Set the flag for socket connected.
this.connected = (e.SocketError == SocketError.Success);
}
private void OnReceive(object sender, SocketAsyncEventArgs e)
{
// Signals the end of receive.
autoSendReceiveEvents[SendOperation].Set();
}
private void OnSend(object sender, SocketAsyncEventArgs e)
{
// Signals the end of send.
autoSendReceiveEvents[ReceiveOperation].Set();
if (e.SocketError == SocketError.Success)
{
if (e.LastOperation == SocketAsyncOperation.Send)
{
// Prepare receiving.
Socket s = e.UserToken as Socket;
byte[] receiveBuffer = new byte[255];
e.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
e.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
s.ReceiveAsync(e);
// Encoding.ASCII.GetString(s..Buffer, completeArgs.Offset, completeArgs.BytesTransferred);
}
}
else
{
this.ProcessError(e);
}
}
/**//// <summary>
/// Close socket in case of failure and throws a SockeException according to the SocketError.
/// </summary>
/// <param name="e">SocketAsyncEventArg associated with the failed operation.</param>
private void ProcessError(SocketAsyncEventArgs e)
{
Socket s = e.UserToken as Socket;
if (s.Connected)
{
// close the socket associated with the client
try
{
s.Shutdown(SocketShutdown.Both);
}
catch (Exception)
{
// throws if client process has already closed
}
finally
{
if (s.Connected)
{
s.Close();
}
}
}
// Throw the SocketException
throw new SocketException((Int32)e.SocketError);
}
/**//// <summary>
/// Exchange a message with the host.
/// </summary>
/// <param name="message">Message to send.</param>
/// <returns>Message sent by the host.</returns>
public String SendReceive(String message)
{
//指示应挂起此线程以使其他等待线程能够执行
System.Threading.Thread.Sleep(0);
if (this.connected)
{
// Create a buffer to send.
Byte[] sendBuffer = Encoding.Default.GetBytes(message);
//StrHelper.Str2AscArr(message);
// Prepare arguments for send/receive operation.
SocketAsyncEventArgs completeArgs = new SocketAsyncEventArgs();
completeArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length);
completeArgs.UserToken = this.clientSocket;
completeArgs.RemoteEndPoint = this.hostEndPoint;
completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);
// Start sending asyncronally.
clientSocket.SendAsync(completeArgs);
// Wait for the send/receive completed.
AutoResetEvent.WaitAll(autoSendReceiveEvents);
StringBuilder resultMsg = new StringBuilder();
resultMsg.Append(Encoding.Default.GetString(completeArgs.Buffer, completeArgs.Offset, completeArgs.BytesTransferred));
while ((completeArgs.UserToken as Socket).Available > 0)
{
clientSocket.ReceiveAsync(completeArgs);
AutoResetEvent.WaitAll(autoSendReceiveEvents);
resultMsg.Append(Encoding.Default.GetString(completeArgs.Buffer, completeArgs.Offset, completeArgs.BytesTransferred));
}
return resultMsg.ToString();
// return Encoding.ASCII.GetString(completeArgs.Buffer, completeArgs.Offset, completeArgs.BytesTransferred);
}
else
{
throw new SocketException((Int32)SocketError.NotConnected);
}
}
IDisposable Members#region IDisposable Members
/**//// <summary>
/// Disposes the instance of SocketClient.
/// </summary>
public void Dispose()
{
autoConnectEvent.Close();
autoSendReceiveEvents[SendOperation].Close();
autoSendReceiveEvents[ReceiveOperation].Close();
if (this.clientSocket.Connected)
{
this.clientSocket.Close();
}
}
#endregion
}
}
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace SocketAsyncClient
{
/**//// <summary>
/// socket客户端
/// 异步实现
/// </summary>
public sealed class SocketClient : IDisposable
{
/**//// <summary>
/// Constants for socket operations.
/// </summary>
private const Int32 ReceiveOperation = 1, SendOperation = 0;
/**//// <summary>
/// The socket used to send/receive messages.
/// </summary>
private Socket clientSocket;
/**//// <summary>
/// Flag for connected socket.
/// </summary>
private Boolean connected = false;
public Boolean Connected
{
get { return connected; }
}
/**//// <summary>
/// Listener endpoint.
/// </summary>
private IPEndPoint hostEndPoint;
/**//// <summary>
/// Signals a connection.
/// </summary>
private AutoResetEvent autoConnectEvent = new AutoResetEvent(false);
// private static AutoResetEvent autoConnectEvent = new AutoResetEvent(false);
/**//// <summary>
/// Signals the send/receive operation.
/// </summary>
// private static AutoResetEvent[] autoSendReceiveEvents = new AutoResetEvent[]
private AutoResetEvent[] autoSendReceiveEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};
/**//// <summary>
/// Create an uninitialized client instance.
/// To start the send/receive processing
/// call the Connect method followed by SendReceive method.
/// </summary>
/// <param name="hostName">Name of the host where the listener is running.</param>
/// <param name="port">Number of the TCP port from the listener.</param>
public SocketClient(String hostName, Int32 port)
{
// Get host related information.
IPHostEntry host = Dns.GetHostEntry(hostName);
// Addres of the host.
IPAddress[] addressList = host.AddressList;
// Instantiates the endpoint and socket.
this.hostEndPoint = new IPEndPoint(addressList[addressList.Length - 1], port);
this.clientSocket = new Socket(this.hostEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
/**//// <summary>
/// Connect to the host.
/// </summary>
/// <returns>True if connection has succeded, else false.</returns>
public void Connect()
{
SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs();
connectArgs.UserToken = this.clientSocket;
connectArgs.RemoteEndPoint = this.hostEndPoint;
connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnect);
clientSocket.ConnectAsync(connectArgs);
autoConnectEvent.WaitOne();
SocketError errorCode = connectArgs.SocketError;
if (errorCode != SocketError.Success)
{
throw new SocketException((Int32)errorCode);
}
}
/**//// <summary>
/// Disconnect from the host.
/// </summary>
public void Disconnect()
{
clientSocket.Disconnect(false);
}
private void OnConnect(object sender, SocketAsyncEventArgs e)
{
// Signals the end of connection.
autoConnectEvent.Set();
// Set the flag for socket connected.
this.connected = (e.SocketError == SocketError.Success);
}
private void OnReceive(object sender, SocketAsyncEventArgs e)
{
// Signals the end of receive.
autoSendReceiveEvents[SendOperation].Set();
}
private void OnSend(object sender, SocketAsyncEventArgs e)
{
// Signals the end of send.
autoSendReceiveEvents[ReceiveOperation].Set();
if (e.SocketError == SocketError.Success)
{
if (e.LastOperation == SocketAsyncOperation.Send)
{
// Prepare receiving.
Socket s = e.UserToken as Socket;
byte[] receiveBuffer = new byte[255];
e.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
e.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
s.ReceiveAsync(e);
// Encoding.ASCII.GetString(s..Buffer, completeArgs.Offset, completeArgs.BytesTransferred);
}
}
else
{
this.ProcessError(e);
}
}
/**//// <summary>
/// Close socket in case of failure and throws a SockeException according to the SocketError.
/// </summary>
/// <param name="e">SocketAsyncEventArg associated with the failed operation.</param>
private void ProcessError(SocketAsyncEventArgs e)
{
Socket s = e.UserToken as Socket;
if (s.Connected)
{
// close the socket associated with the client
try
{
s.Shutdown(SocketShutdown.Both);
}
catch (Exception)
{
// throws if client process has already closed
}
finally
{
if (s.Connected)
{
s.Close();
}
}
}
// Throw the SocketException
throw new SocketException((Int32)e.SocketError);
}
/**//// <summary>
/// Exchange a message with the host.
/// </summary>
/// <param name="message">Message to send.</param>
/// <returns>Message sent by the host.</returns>
public String SendReceive(String message)
{
//指示应挂起此线程以使其他等待线程能够执行
System.Threading.Thread.Sleep(0);
if (this.connected)
{
// Create a buffer to send.
Byte[] sendBuffer = Encoding.Default.GetBytes(message);
//StrHelper.Str2AscArr(message);
// Prepare arguments for send/receive operation.
SocketAsyncEventArgs completeArgs = new SocketAsyncEventArgs();
completeArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length);
completeArgs.UserToken = this.clientSocket;
completeArgs.RemoteEndPoint = this.hostEndPoint;
completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);
// Start sending asyncronally.
clientSocket.SendAsync(completeArgs);
// Wait for the send/receive completed.
AutoResetEvent.WaitAll(autoSendReceiveEvents);
StringBuilder resultMsg = new StringBuilder();
resultMsg.Append(Encoding.Default.GetString(completeArgs.Buffer, completeArgs.Offset, completeArgs.BytesTransferred));
while ((completeArgs.UserToken as Socket).Available > 0)
{
clientSocket.ReceiveAsync(completeArgs);
AutoResetEvent.WaitAll(autoSendReceiveEvents);
resultMsg.Append(Encoding.Default.GetString(completeArgs.Buffer, completeArgs.Offset, completeArgs.BytesTransferred));
}
return resultMsg.ToString();
// return Encoding.ASCII.GetString(completeArgs.Buffer, completeArgs.Offset, completeArgs.BytesTransferred);
}
else
{
throw new SocketException((Int32)SocketError.NotConnected);
}
}
IDisposable Members#region IDisposable Members
/**//// <summary>
/// Disposes the instance of SocketClient.
/// </summary>
public void Dispose()
{
autoConnectEvent.Close();
autoSendReceiveEvents[SendOperation].Close();
autoSendReceiveEvents[ReceiveOperation].Close();
if (this.clientSocket.Connected)
{
this.clientSocket.Close();
}
}
#endregion
}
}