在基于.NET的网络服务端的开发中,我们用到和听到的最多的恐怕就是异步Socket了。异步Socket的性能比同步高出很多,但是编写代码比较复杂。因此异步Socket也是网络上讨论比较多的话题。
今天,我们就来讨论一下如何用异步Socket开发网络应用。在此之前我们先讨论两个问题。
一、异步Socket是如何工作的:
那异步Socket是如何工作的呢?我以接收一条消息来说明这个问题。首先,程序向系统投递一个接收数据的请求,并为其指定一个数据缓冲区和回调函数,回调函数用来指示当数据到达后将如何处理,然后我们的程序继续执行下去,当有数据到达的时候,系统将数据读入缓冲区,并执行回调函数,处理这条消息。我们并不需要关心这条消息何时到达。
二、什么情况下我们用异步Socket:
有些人认为,异步Socket的性能比同步Socket的性能高很多,应该在各种环境下都用异步Socket,其实不然。在某些环境下面。异步反到比同步的性能低,那么在哪些情况下会这样呢?
1、 客户端Socket。
2、 服务端连接数比较少。
3、 连接数很多,但都是短连接。
在这些环境下,我们用同步Socket不但可以简化代码,而且性能并不会比异步Socket低。但在服务端连接比较多而且是长连接的情况下,我们就要使用异步Socket。
现在我们来看看如何用异步Socket编程。
服务端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
namespace CutImage
{
public class MySocket
{
Socket _server;
public MySocket()
{
_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_server.Bind(new IPEndPoint(IPAddress.Any,8808));
_server.Listen(100);
Thread th = new Thread(new ThreadStart(WriteConnetion));
th.Start();
}
/// <summary>
/// 等待客户端连接的方法
/// </summary>
void WriteConnetion()
{
while(true)
{
Socket s = _server.Accept();
User user = new User();
user.Userid =Guid.NewGuid().ToString();
user.mysocket = s;
s.BeginReceive(user.msg, 0, user.msg.Length, SocketFlags.None, new AsyncCallback(Recivecallback),user);//向系统投递一个接受信息的请求 Recivecallback为回调函数
}
}
/// <summary>
/// 接受信息的回调函数
/// </summary>
/// <param name="ar"></param>
void Recivecallback(IAsyncResult ar)
{
User user = (User)ar.AsyncState;
Socket _customersocket=user.mysocket;
int recivecount=0;
try
{
recivecount = _customersocket.EndReceive(ar);
}
catch (SocketException)//连接断开
{
Close(user);
}catch
{
}
if(recivecount>0)
{
byte[] buffer = new byte[recivecount];//收到的信息
Buffer.BlockCopy(user.msg, 0, buffer, 0, recivecount);
GetMsg(user, buffer);//这个函数用来处理接收到的信息
try
{
user.mysocket.BeginReceive(user.msg, 0, user.msg.Length, SocketFlags.None, new AsyncCallback(Recivecallback), user);
}
catch (SocketException)
{
Close(user);
}
catch
{
}
}
else//如果接收到0字节的数据说明客户端关闭了Socket,那我们也要关闭Socket
{
Close(user);
}
}
/// <summary>
/// 断开连接
/// </summary>
/// <param name="u"></param>
void Close(User u)
{
Console.WriteLine(u.Userid + "连接断开");
return;
}
/// <summary>
/// 收到信息的处理函数
/// </summary>
/// <param name="u"></param>
/// <param name="msg"></param>
void GetMsg(User u,byte[] msg)
{
string _msg=Encoding.UTF8.GetString(msg);
Console.WriteLine(u.Userid + "收到数据:" + _msg);
SendMsg(u, msg);
}
/// <summary>
/// 发送信息
/// </summary>
/// <param name="user"></param>
/// <param name="msg"></param>
void SendMsg(User user,byte[] msg)
{
try
{
user.mysocket.BeginSend(msg, 0, msg.Length, SocketFlags.None, new AsyncCallback(Sendcallback), user);
string str=Encoding.UTF8.GetString(msg);
Console.WriteLine(user.Userid + "发送数据:" + str);
}
catch (SocketException)
{
Close(user);
}
}
/// <summary>
/// 发送信息的回调
/// </summary>
/// <param name="ar"></param>
void Sendcallback(IAsyncResult ar)
{
User u = (User)ar.AsyncState;
try
{
u.mysocket.EndSend(ar);
}
catch (System.Exception ex)
{
}
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
namespace CutImage
{
public class MySocket
{
Socket _server;
public MySocket()
{
_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_server.Bind(new IPEndPoint(IPAddress.Any,8808));
_server.Listen(100);
Thread th = new Thread(new ThreadStart(WriteConnetion));
th.Start();
}
/// <summary>
/// 等待客户端连接的方法
/// </summary>
void WriteConnetion()
{
while(true)
{
Socket s = _server.Accept();
User user = new User();
user.Userid =Guid.NewGuid().ToString();
user.mysocket = s;
s.BeginReceive(user.msg, 0, user.msg.Length, SocketFlags.None, new AsyncCallback(Recivecallback),user);//向系统投递一个接受信息的请求 Recivecallback为回调函数
}
}
/// <summary>
/// 接受信息的回调函数
/// </summary>
/// <param name="ar"></param>
void Recivecallback(IAsyncResult ar)
{
User user = (User)ar.AsyncState;
Socket _customersocket=user.mysocket;
int recivecount=0;
try
{
recivecount = _customersocket.EndReceive(ar);
}
catch (SocketException)//连接断开
{
Close(user);
}catch
{
}
if(recivecount>0)
{
byte[] buffer = new byte[recivecount];//收到的信息
Buffer.BlockCopy(user.msg, 0, buffer, 0, recivecount);
GetMsg(user, buffer);//这个函数用来处理接收到的信息
try
{
user.mysocket.BeginReceive(user.msg, 0, user.msg.Length, SocketFlags.None, new AsyncCallback(Recivecallback), user);
}
catch (SocketException)
{
Close(user);
}
catch
{
}
}
else//如果接收到0字节的数据说明客户端关闭了Socket,那我们也要关闭Socket
{
Close(user);
}
}
/// <summary>
/// 断开连接
/// </summary>
/// <param name="u"></param>
void Close(User u)
{
Console.WriteLine(u.Userid + "连接断开");
return;
}
/// <summary>
/// 收到信息的处理函数
/// </summary>
/// <param name="u"></param>
/// <param name="msg"></param>
void GetMsg(User u,byte[] msg)
{
string _msg=Encoding.UTF8.GetString(msg);
Console.WriteLine(u.Userid + "收到数据:" + _msg);
SendMsg(u, msg);
}
/// <summary>
/// 发送信息
/// </summary>
/// <param name="user"></param>
/// <param name="msg"></param>
void SendMsg(User user,byte[] msg)
{
try
{
user.mysocket.BeginSend(msg, 0, msg.Length, SocketFlags.None, new AsyncCallback(Sendcallback), user);
string str=Encoding.UTF8.GetString(msg);
Console.WriteLine(user.Userid + "发送数据:" + str);
}
catch (SocketException)
{
Close(user);
}
}
/// <summary>
/// 发送信息的回调
/// </summary>
/// <param name="ar"></param>
void Sendcallback(IAsyncResult ar)
{
User u = (User)ar.AsyncState;
try
{
u.mysocket.EndSend(ar);
}
catch (System.Exception ex)
{
}
}
}
}
客户端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect("127.0.0.1", 8808);
for(int i=1;i<51;i++)
{
//发送信息
byte[] buffer = Encoding.UTF8.GetBytes("Login|"+i);
client.Send(buffer, 0, buffer.Length, SocketFlags.None);
//接受信息
byte[] buffer1=new byte[1024];
client.Receive(buffer1, 0, buffer1.Length, SocketFlags.None);
string str=Encoding.UTF8.GetString(buffer);
Console.WriteLine("收到服务端返回信息:"+str);
}
client.Connect("127.0.0.1", 8808);
for(int i=1;i<51;i++)
{
//发送信息
byte[] buffer = Encoding.UTF8.GetBytes("Login|"+i);
client.Send(buffer, 0, buffer.Length, SocketFlags.None);
//接受信息
byte[] buffer1=new byte[1024];
client.Receive(buffer1, 0, buffer1.Length, SocketFlags.None);
string str=Encoding.UTF8.GetString(buffer);
Console.WriteLine("收到服务端返回信息:"+str);
}