Socket网络应用程序如同一般文件I/O一样在数据存取未完成的时候,整个应用程序会停滞,直到网络操作完全成功为止。若是遇上不佳的网络环境,这种情形将会严重影响整个网络程序的运作。对于网络延迟,.NET提供了自己的一组解决方法,异步操作。
Socket类提供的方法成员中包含一组专门用来进行异步操作的Socket方法。这些方法以成对出现:BeginConnect 与 EndConnect 提供异步联机功能、BeginAccept 与 EndAccept 提供异步接受请求、 BeginReceive与 EndReceive 异步接收数据、BeginSend与EndSend 异步发送数据。
其实这些方法和同步相当类似,最大的差异在于AsyncCallback类派生对象,上述的异步方法接受一个AsyncCallback对象,封装回调方法,并在Socket网络操作完成之后,返回IAsyncResult接口对象。此对象被当作参数。传入回调的方法,回调的方法调用结束相关异步方法,并且传入IAsyncResult,取得相关的异步操作信息。
服务端代码示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace AsyncSocketServer
{
class Program
{
const string strSuffix = "$";//定义结尾
Thread newThread;//开启线程
static Socket socket;
static int port = 8003;//定义侦听端口
//允许线程通过发信号互相通信。通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。
public static ManualResetEvent manualResetEvent = new ManualResetEvent(false);//线程通过发信号互相通信,通知一个或多个正在等待的线程已发生事件
private const int MAX_SOCKET = 10;
/// <summary>
/// 服务器端
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Thread newThread = new Thread(new ThreadStart(BebinListen));
newThread.Start();
}
/// <summary>
/// 获取服务器地址
/// </summary>
/// <returns></returns>
private static IPAddress GetServerIp()
{
IPHostEntry iPHostEntry = Dns.GetHostEntry(Dns.GetHostName());
return iPHostEntry.AddressList[0];
}
//异步传递的状态对象
public class StateOject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder stringBuilder = new StringBuilder();
}
/// <summary>
/// 开始监听
/// </summary>
private static void BebinListen()
{
//定义监听
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ServerIp = GetServerIp();
IPEndPoint ipEndPoint = new IPEndPoint(ServerIp, port);
socket.Bind(ipEndPoint);
Console.WriteLine(ipEndPoint.ToString() + "正在监听...");
socket.Listen(5);
//接收消息
byte[] byteMessage = new byte[100];
while (true)
{
try
{
manualResetEvent.Reset();
manualResetEvent.WaitOne();
}
catch (Exception exception)
{ }
}
}
/// <summary>
/// 异步接收回调函数
/// </summary>
/// <param name="iAsyncResult"></param>
private void AcceptCallback(IAsyncResult iAsyncResult)
{
Socket listener = (Socket)iAsyncResult.AsyncState;
Socket client = listener.EndAccept(iAsyncResult);
manualResetEvent.Set();
//StateObject:一个用户定义对象,其中包含接收操作的相关信息。当操作完成时,
//此对象会被传递给EndReceive 委托。
StateOject state = new StateOject();
state.workSocket = client;
//远端信息
EndPoint tempRemoteEP = client.RemoteEndPoint;
IPEndPoint tempRemoteIP = (IPEndPoint)tempRemoteEP;
string rempIp = tempRemoteIP.Address.ToString();
string rempPort = tempRemoteIP.Port.ToString();
IPHostEntry host = Dns.GetHostEntry(tempRemoteIP.Address);
string hostName = host.HostName;
string msg = "接受[" + hostName + "]" + rempIp + ":"+rempPort+"远程计算机连接!";
Console.WriteLine(msg.ToString()+"\r\n");
client.BeginReceive(state.buffer, 0, StateOject.BufferSize, 0, new AsyncCallback(SendCallback), state);
}
/// <summary>
/// 异步接收回调函数
/// </summary>
/// <param name="iAsyncResult"></param>
private void readCallback(IAsyncResult iAsyncResult)
{
StateOject state = (StateOject)iAsyncResult.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(iAsyncResult);
if (bytesRead > 0)
{
string msg = Encoding.Default.GetString(state.buffer, 0, bytesRead);
state.stringBuilder.Append(msg);
string content = state.stringBuilder.ToString();
EndPoint tempRemoteEP = handler.RemoteEndPoint;
IPEndPoint tempRemoteIp = (IPEndPoint)tempRemoteEP;
string rempIp = tempRemoteIp.Address.ToString();
string rempPort = tempRemoteIp.Port.ToString();
IPHostEntry host = Dns.GetHostEntry(tempRemoteIp.Address);
string hostName = host.HostName;
string strMsg = "(" + DateTime.Now.ToString() + ")接收来自" + hostName + ":";
strMsg += DelStrSuffix(strMsg);
Console.WriteLine(strMsg.ToString());
}
}
/// <summary>
/// 异步发送回调函数
/// </summary>
/// <param name="iAsyncResult"></param>
private void SendCallback(IAsyncResult iAsyncResult)
{
try
{
Socket handler = (Socket)iAsyncResult.AsyncState;
int bytesSent = handler.EndSend(iAsyncResult);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (SocketException socketException)
{
Console.WriteLine(socketException.ToString());
}
}
/// <summary>
/// 异步发送
/// </summary>
/// <param name="handleer"></param>
/// <param name="data"></param>
private void Send(Socket handler, string data)
{
byte[] byteDate = Encoding.Default.GetBytes(data + strSuffix);
handler.Send(byteDate);
}
/// <summary>
/// 去除字符串结尾的特殊字符
/// </summary>
/// <param name="strContent"></param>
/// <returns></returns>
private string DelStrSuffix(string strContent)
{
int ed = strContent.LastIndexOf(strSuffix);
string content = strContent.Remove(ed);
return content;
}
}
}
客户端代码示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace AsyncSocketClient
{
class Program
{
const string strSuffix = "$";
static Socket socket;
int numbyte = 1024;//一次接收到的字节数。
int port=8003;
/// <summary>
/// 客户端
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
SnedMessage();
}
/// <summary>
/// 获取本机IP地址
/// </summary>
/// <returns></returns>
private static IPAddress GetClientIp()
{
IPHostEntry ipHostEntry = Dns.GetHostEntry(Dns.GetHostName());
return ipHostEntry.AddressList[0];
}
//发送信息
private static void SnedMessage()
{
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress serverIp=GetClientIp();
int serverPort = 8003;
IPEndPoint remoteIep = new IPEndPoint(serverIp, serverPort);
socket.Connect(remoteIep);
IPEndPoint tempLocalPoint = (IPEndPoint)socket.LocalEndPoint;
string msg= "端口:" + tempLocalPoint.Port.ToString() + "正在监听......";
}
catch
{
Console.WriteLine( "无法连接到目标计算机!");
return;
}
try
{
Console.WriteLine( "正在发送信息!");
string message ="this is test example!!!!!";
SendInfo(message);
}
catch //异常处理
{
Console.WriteLine("无法发送信息到目标计算机!");
}
}
//发送信息
private static void SendInfo(string message)
{
byte[] byteMessage = Encoding.Default.GetBytes(message + strSuffix);
socket.Send(byteMessage);
//远端信息
EndPoint tempRemoteEP = socket.RemoteEndPoint;
IPEndPoint tempRemoteIP = (IPEndPoint)tempRemoteEP;
string rempip = tempRemoteIP.Address.ToString();
string remoport = tempRemoteIP.Port.ToString();
IPHostEntry host = Dns.GetHostEntry(tempRemoteIP.Address);
string HostName = host.HostName;
//发送信息
string time1 = DateTime.Now.ToString();
//发送完了,直接接收
StringBuilder sb = new StringBuilder();
while (true)
{
Console.WriteLine("正在等待接收信息...");
byte[] bytes = new byte[1000];
int recvbytes = socket.Receive(bytes);
string strmsg = Encoding.Default.GetString(bytes);
sb.Append(strmsg);
if (sb.ToString().IndexOf(strSuffix) > -1)
{
break;
}
}
Console.WriteLine("接收信息完毕!");
//代码解码,对返回的信息进行处理
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
//去除字符串结尾特殊符号
private string DelStrSuffix(string strcontent)
{
int ed = strcontent.LastIndexOf(strSuffix);
string content = strcontent.Remove(ed);
return content;
}
}
}