在(三)中我们用多线程简单实现了异步,这里用微软为我们提供的IAsyncResult模式来实现
现在代码增多了,把处理套接字的部分单独创建一个类SocketServer
代码如下,同时仍然保留了同步的Listen方法,这里异步的监听命名为AsyncListen
class SocketServer
...{
private int _port;
private string _ip;
private string _hostName;
private int _backlog; //队列连接数
private IPEndPoint ipEndPoint;
private IPAddress ipAddress;
private IPHostEntry ipHostEntry;
private Socket listener;
public int Port
...{
get ...{ return _port; }
set ...{ _port = value; }
}
public int BackLog
...{
get ...{ return _backlog; }
set ...{ _backlog = value; }
}
public string IP
...{
get ...{ return _ip; }
set ...{ _ip = value; }
}
public string HostName
...{
get ...{ return _hostName; }
set ...{ _hostName = value; }
} 

public UploadServer()
...{
listener = null;
_ip = "127.0.0.1";
_port = 7788;
_backlog = 10;
_hostName = String.Empty;
}

/**//// <summary>
/// 初始化服务器地址
/// </summary>
private void InitIPInfo()
...{
if (_ip == String.Empty)
...{
if (_hostName != String.Empty)
...{
ipHostEntry = Dns.GetHostEntry(_hostName);
ipAddress = ipHostEntry.AddressList[0];
}
else
...{
throw new Exception("未指定有效服务器地址");
}
}
else
...{
ipAddress = IPAddress.Parse(_ip);
ipHostEntry = Dns.GetHostEntry(ipAddress);
}
ipEndPoint = new IPEndPoint(ipAddress, _port);
}
public void Listen()
...{
InitIPInfo();
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(_backlog);
Console.WriteLine("服务启动,开始监听");
Console.WriteLine("等待客户端连接...");
Socket clientSocket = listener.Accept();
Console.WriteLine("建立连接");
// 接受数据
byte[] buffer = new byte[1024];
clientSocket.Receive(buffer);
Console.WriteLine("接受客户端信息:{0}", Encoding.GetEncoding("gb2312").GetString(buffer));
//回复客户端
byte[] backBuffer = new byte[1024];
string backString = "收到数据";
backBuffer = Encoding.GetEncoding("gb2312").GetBytes(backString);
clientSocket.Send(backBuffer);
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
Console.WriteLine("关闭客户端连接");
}
public void AsyncListen()
...{
InitIPInfo();
listener = new Socket(ipEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(_backlog);
Console.WriteLine("服务启动,开始监听");
Console.WriteLine("等待客户端连接...");
listener.BeginAccept(new AsyncCallback(acceptCallback), listener);
}
private void acceptCallback(IAsyncResult ar) 
...{
Socket listener = (Socket)ar.AsyncState;
Socket clientSocket = listener.EndAccept(ar); //获得客户端套接字接口
Console.WriteLine("建立连接");
StateObject state = new StateObject();
state.WorkSocket = clientSocket;
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state); //开始接受数据
}
public class StateObject
...{
public Socket WorkSocket = null;
public static int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
}
//结束挂起的异步读取
public static void readCallback(IAsyncResult ar)
...{
StateObject state = (StateObject)ar.AsyncState;
Socket clientSocket = state.WorkSocket;
if (clientSocket.Connected)
...{
int read = clientSocket.EndReceive(ar);//结束挂起的异步读取

//一直接受数据到没有为止
if (read > 0)
...{
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state);
}
Console.WriteLine("接受客户端信息:{0}", Encoding.GetEncoding("gb2312").GetString(state.buffer));
//回复客户端
byte[] backBuffer = new byte[1024];
string backString = "收到数据";
backBuffer = Encoding.GetEncoding("gb2312").GetBytes(backString);
clientSocket.Send(backBuffer);
clientSocket.Close();
}
else
...{
Console.WriteLine("连接已经关闭!");
}
}
}在Program.cs如下调用
SocketServer us = new SocketServer();
us.AsyncListen();
OK运行查看效果
上面的例子基本实现,实际存在问题还很多
比如
如果客户端传送的数据一次接受不完
没有服务器端向客户端发送信息
而且判断是否接受完客户端数据上面的例子也有问题,下面来完善一下
class SocketServer
...{
private int _port;
private string _ip;
private string _hostName;
private int _backlog; //队列连接数
private IPEndPoint ipEndPoint;
private IPAddress ipAddress;
private IPHostEntry ipHostEntry;
private Socket listener;
private static ManualResetEvent allDone = new ManualResetEvent(false);
public int Port
...{
get ...{ return _port; }
set ...{ _port = value; }
}
public int BackLog
...{
get ...{ return _backlog; }
set ...{ _backlog = value; }
}
public string IP
...{
get ...{ return _ip; }
set ...{ _ip = value; }
}
public string HostName
...{
get ...{ return _hostName; }
set ...{ _hostName = value; }
}
public class StateObject
...{
public Socket WorkSocket = null;
public static int BufferSize = 2;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
public SocketServer()
...{
listener = null;
_ip = "127.0.0.1";
_port = 7788;
_backlog = 10;
_hostName = String.Empty;
}

/**//// <summary>
/// 初始化服务器地址
/// </summary>
private void InitIPInfo()
...{
if (_ip == String.Empty)
...{
if (_hostName != String.Empty)
...{
ipHostEntry = Dns.GetHostEntry(_hostName);
ipAddress = ipHostEntry.AddressList[0];
}
else
...{
throw new Exception("未指定有效服务器地址");
}
}
else
...{
ipAddress = IPAddress.Parse(_ip);
ipHostEntry = Dns.GetHostEntry(ipAddress);
}
ipEndPoint = new IPEndPoint(ipAddress, _port);
}
public void Listen()
...{
InitIPInfo();
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(_backlog);
Console.WriteLine("服务启动,开始监听");
Console.WriteLine("等待客户端连接...");
Socket clientSocket = listener.Accept();
Console.WriteLine("建立连接");
// 接受数据
byte[] buffer = new byte[1024];
clientSocket.Receive(buffer);
Console.WriteLine("接受客户端信息:{0}", Encoding.GetEncoding("gb2312").GetString(buffer));
//回复客户端
byte[] backBuffer = new byte[1024];
string backString = "收到数据";
backBuffer = Encoding.GetEncoding("gb2312").GetBytes(backString);
clientSocket.Send(backBuffer);
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
Console.WriteLine("关闭客户端连接");
}
public void AsyncListen()
...{
InitIPInfo();
listener = new Socket(ipEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
...{
listener.Bind(ipEndPoint);
listener.Listen(_backlog);
Console.WriteLine("服务启动,开始监听");
Console.WriteLine("等待客户端连接...");
while (true)
...{
allDone.Reset();
listener.BeginAccept(new AsyncCallback(acceptCallback), listener);
allDone.WaitOne();
}
}
catch (Exception ex)
...{
Console.WriteLine("发生错误:"+ex.Message);
}
}
private void acceptCallback(IAsyncResult ar) 
...{
Console.WriteLine("acceptCallback 被调用");
Socket listener = (Socket)ar.AsyncState;
Socket clientSocket = listener.EndAccept(ar); //获得客户端套接字接口
Console.WriteLine("建立连接");
allDone.Set();
StateObject state = new StateObject();
state.WorkSocket = clientSocket;
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state); //开始接受数据
}
public void readCallback(IAsyncResult ar)
...{
StateObject state = (StateObject)ar.AsyncState;
Socket clientSocket = state.WorkSocket;
try
...{
int read = 0;
read = clientSocket.EndReceive(ar);//结束挂起的异步读取
if (read > 0)
...{
state.sb.Append(Encoding.GetEncoding("gb2312").GetString(state.buffer, 0, read));
Console.WriteLine(state.sb.ToString());
if (state.sb.ToString().IndexOf("<end>") > -1)
...{
Console.WriteLine("已经接收完数据");
//回复客户端
byte[] backBuffer = new byte[1024];
string backString = "已经收到数据";
backBuffer = Encoding.GetEncoding("gb2312").GetBytes(backString);
clientSocket.BeginSend(backBuffer, 0, backBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallback), state);
}
else
...{
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(readCallback), state);
}
}
}
catch (SocketException se)
...{
if (se.ErrorCode == 10054)
...{
Console.WriteLine("客户端已断开连接!");
}
else
...{
Console.WriteLine(se.Message);
}
}
catch (Exception ex)
...{
Console.WriteLine(ex.Message);
}
}
private void SendCallback(IAsyncResult ar)
...{
Console.WriteLine("SendCallback 被调用");
try
...{
StateObject state = (StateObject)ar.AsyncState;
Socket handle = state.WorkSocket;
int bytesSent = handle.EndSend(ar);
Console.WriteLine("发送到客户端 {0}", bytesSent);
Console.WriteLine("接受客户端信息:{0}",state.sb.ToString() );
handle.Shutdown(SocketShutdown.Both);
handle.Close();
}
catch (Exception e)
...{
Console.WriteLine(e.ToString());
}
}
}
这里判断客户端传送数据是否接受完成时个比较麻烦的问题
这里在客户端传入的字符串中用了<end>标志来判断
如果使用EndReceive的返回值是否大于1来判断会出现无法调用委托方法的情况也不报错
因为当没有数据传输到服务器端的时候BeginReceive并不会调用委托
自己感觉靠添加额外定制符号的办法不是很让人舒服,暂时也没有其他好的解决办法,如果有朋友知道告诉我一下哈:)
下面贴出客户端修改为异步以后的代码
public class StateObject
...{
public Socket workSocket = null;
public static int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}

class SocketClient
...{
private int _port;
private string _ip;
private string _hostName;
private IPEndPoint ipEndPoint;
private IPAddress ipAddress;
private IPHostEntry ipHostEntry;
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
private static ManualResetEvent receiveDone = new ManualResetEvent(false);
private static String response = String.Empty; //服务器返回的信息
public int Port
...{
get ...{ return _port; }
set ...{ _port = value; }
}
public string IP
...{
get ...{ return _ip; }
set ...{ _ip = value; }
}
public string HostName
...{
get ...{ return _hostName; }
set ...{ _hostName = value; }
}
private void InitIPInfo()
...{
if (_ip == String.Empty)
...{
if (_hostName != String.Empty)
...{
ipHostEntry = Dns.GetHostEntry(_hostName);
ipAddress = ipHostEntry.AddressList[0];
}
else
...{
throw new Exception("未指定有效服务器地址");
}
}
else
...{
ipAddress = IPAddress.Parse(_ip);
ipHostEntry = Dns.GetHostEntry(ipAddress);
}
ipEndPoint = new IPEndPoint(ipAddress, _port);
}
public UploadClient()
...{
_ip = "127.0.0.1";
_port = 7788;
_hostName = String.Empty;
}
public void Connect()
...{
InitIPInfo();
try
...{
/**////创建socket并连接到服务器
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine("等待连接…");
serverSocket.Connect(ipEndPoint);//连接到服务器
Console.WriteLine("已连接");
//发送数据
byte[] buffer = new byte[1024];
buffer = Encoding.GetEncoding("gb2312").GetBytes("Godling is a good man!<end>");
serverSocket.Send(buffer);
//接受数据
byte[] bufferGet = new byte[1024];
serverSocket.Receive(bufferGet);
Console.WriteLine("接受服务端信息:{0}", Encoding.GetEncoding("gb2312").GetString(bufferGet));
serverSocket.Shutdown(SocketShutdown.Both);
serverSocket.Close();
}
catch (ArgumentNullException e)
...{
Console.WriteLine("argumentNullException: {0}", e);
}
catch (SocketException e)
...{
Console.WriteLine("SocketException:{0}", e);
}
Console.WriteLine("Press Enter to Exit");
}
//开始异步连接
public void AsyncConnect()
...{
try
...{
InitIPInfo();
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallback), serverSocket);
connectDone.WaitOne(); //阻止运行直到连接成功
//发送数据
string data = "你能收到我吗?<end>";
byte[] byteData = Encoding.GetEncoding("gb2312").GetBytes(data);
serverSocket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), serverSocket);
sendDone.WaitOne();

StateObject state = new StateObject();
state.workSocket = serverSocket;
serverSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
receiveDone.WaitOne();
Console.WriteLine("接收到服务器信息:{0}", response);
serverSocket.Shutdown(SocketShutdown.Both);
serverSocket.Close();
}
catch(Exception ex)
...{
Console.WriteLine("发生异常"+ex.Message);
}
}
// 连接完成回调方法
private void ConnectCallback(IAsyncResult ar)
...{
try
...{
Socket serverSocket = (Socket)ar.AsyncState;
serverSocket.EndConnect(ar);
Console.WriteLine("已连接到{0}",serverSocket.RemoteEndPoint.ToString());
connectDone.Set();
}
catch (Exception e)
...{
Console.WriteLine("连接错误!"+e.ToString());
}
}
// 数据发送回调方法
private static void SendCallback(IAsyncResult ar)
...{
try
...{
Socket serverSocket = (Socket)ar.AsyncState;
int bytesSent = serverSocket.EndSend(ar);
Console.WriteLine("向服务器发送数据 {0} bytes", bytesSent);
sendDone.Set();
}
catch (Exception e)
...{
Console.WriteLine(e.ToString());
}
}
// 接收数据回调方法
private static void ReceiveCallback(IAsyncResult ar)
...{
StateObject state = (StateObject)ar.AsyncState;
Socket serverSocket = state.workSocket;
int read = 0;
if (serverSocket.Connected)
...{
read = serverSocket.EndReceive(ar);
}
if (read > 0)
...{
state.sb.Append(Encoding.GetEncoding("gb2312").GetString(state.buffer, 0, read));
try
...{
serverSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
}
catch (SocketException se)
...{
if (se.ErrorCode == 10054)
...{
Console.WriteLine("远程主机已经断开连接!");
}
}
}
else
...{
if (state.sb.Length > 1)
...{
response = state.sb.ToString();
}
receiveDone.Set();
}
}



}
本文介绍了一个使用.NET框架实现的异步Socket服务器与客户端程序。通过IAsyncResult模式,文章详细展示了如何构建异步监听和处理客户端连接请求的方法。此外,还讨论了如何确保数据完整接收及发送,并提供了一种通过特定标记判断数据接收完毕的方式。

1147

被折叠的 条评论
为什么被折叠?



