最近半年以来都在从事suse10下的C++开发,开发工具也从豪门visual studio10降到了代码查看工具source insight。不过不得不说source insight阅读代码的效率绝对超过visual studio,虽然visual studio也能设置哪些功能,但真心没source insight顺手。不过悲剧的就是写代码的支持比文本好不了多少,调试的话,只能上传到suse10服务器上去然后慢慢的gdb调试了,最头大的就是那个makefile的编写,实在让人累。还是怀念windows下那种豪华的日子。
废话不多说了,我写这篇文章不是为了诉苦的,只是为了继续写网络这边的。以前写过windows下的C++的网络编程的一些日子,虽然也被喷过不少,不过今天我还是要来写网络编程,只是语言更换为豪华的C#。之所以说C#豪华,相信同时使用C#与C++的人能体会到。
frame work实在是太强大了,基本我就关注一点点东西就行了,很多类似工具的东西都是可以直接拿过来使用,而且最为关键的是我们在天朝,不用花钱用企业版,小小鄙视下自己,不过我还是会继续支持山寨盗版,谁让我是屌丝呢。
今天文章中写的是异步,纯粹的异步,当然很多人看来很简单了,而且里面很多东西值得商榷,不过说真的,我真心感谢C#的线程池,不然我还要自己去写个threadpool。而且我没办法保证我写的没问题。
直接上代码了,不讲思路了,没时间,最近太忙,已经几天没睡好了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace PPT.Comm
{
///
<summary>
///
接收数据流
///
</summary>
///
<param name="m_pSocket">
异步套接字
</param>
///
<param name="m_pDatagram">
接收到的数据流
</param>
public
delegate
void AsyncDataAcceptedEventHandler(AsyncSocket m_pSocket,
byte[] m_pDatagram);
///
<summary>
///
发送完毕
///
</summary>
///
<param name="m_pSocket">
异步套接字
</param>
///
<param name="m_pIsSuccess">
发送结果
</param>
public
delegate
void AsyncDataSendedEventHandler(AsyncSocket m_pSocket,
bool m_pIsSuccess);
///
<summary>
///
接收连接委托
///
</summary>
///
<param name="m_pSocket">
异步套接字
</param>
public
delegate
void AsyncSocketAcceptEventHandler(AsyncSocket m_pSocket);
///
<summary>
///
关闭连接委托
///
</summary>
///
<param name="m_pSocket">
异步套接字
</param>
public
delegate
void AsyncSocketClosedEventHandler(AsyncSocket m_pSocket);
///
<summary>
///
State object for receiving data from remote device.
///
</summary>
class StateObject
{
//
Client socket.
public Socket workSocket =
null;
//
Size of receive buffer.
public
const
int BufferSize =
1024 *
256;
//
Receive buffer.
public
byte[] buffer =
new
byte[BufferSize];
//
Received data string.
public StringBuilder sb =
new StringBuilder();
}
///
<summary>
///
异步SOCKET
///
</summary>
public
class AsyncSocket
{
#region 私有字段 成员
private Socket m_socket =
null;
//
socket
string m_id =
"";
//
socket唯一标识,GUID
private
readonly
bool m_isSerevr;
//
服务器标志位
private
int m_iBackBag;
private
string m_ipAddress;
private
int m_port;
private AsyncDataAcceptedEventHandler m_onAsyncDataAcceptedEvent =
null;
//
接收数据流
private AsyncDataSendedEventHandler m_onAsyncDataSendedEvent =
null;
//
发送结束
private AsyncSocketAcceptEventHandler m_onAsyncSocketAcceptEvent =
null;
//
接收连接
private AsyncSocketClosedEventHandler m_onAsyncSocketClosedEvent =
null;
//
关闭连接
#endregion
#region 公共属性 成员
///
<summary>
///
获取SOCKET标志位
///
</summary>
public
string ID
{
get
{
return m_id;
}
}
///
<summary>
///
设置或获取机器标志位
///
</summary>
public
string MachineKey
{
set;
get;
}
///
<summary>
///
获取、设置连接对象
///
</summary>
public Socket LinkObject
{
get
{
return m_socket;
}
set
{
m_socket = value;
}
}
///
<summary>
///
设置或获取线程退出标识
///
</summary>
public
bool IsExit {
set;
get; }
#endregion
#region 公共事件 成员
///
<summary>
///
连接关闭事件
///
</summary>
public
event AsyncSocketClosedEventHandler AsyncSocketClosedEvent
{
add
{
m_onAsyncSocketClosedEvent += value;
}
remove
{
m_onAsyncSocketClosedEvent -= value;
}
}
///
<summary>
///
连接接收事件
///
</summary>
public
event AsyncSocketAcceptEventHandler AsyncSocketAcceptEvent
{
add
{
m_onAsyncSocketAcceptEvent += value;
}
remove
{
m_onAsyncSocketAcceptEvent -= value;
}
}
///
<summary>
///
数据接收完成事件
///
</summary>
public
event AsyncDataAcceptedEventHandler AsyncDataAcceptedEvent
{
add
{
this.m_onAsyncDataAcceptedEvent += value;
}
remove
{
this.m_onAsyncDataAcceptedEvent -= value;
}
}
///
<summary>
///
数据发送完成事件
///
</summary>
public
event AsyncDataSendedEventHandler AsyncDataSendedEvent
{
add
{
m_onAsyncDataSendedEvent += value;
}
remove
{
m_onAsyncDataSendedEvent -= value;
}
}
#endregion
#region 构造函数 成员
///
<summary>
///
构造函数
///
</summary>
///
<param name="m_pHostAddrss">
主机地址,可为机器名或者IP
</param>
///
<param name="m_pHostPort">
主机端口
</param>
///
<param name="m_pIsAsServer">
是否作为服务器,默认为false
</param>
///
<param name="m_pICount">
支持多少个客户端
</param>
public AsyncSocket(
string m_pHostAddrss,
int m_pHostPort,
bool m_pIsAsServer =
false,
int m_pIBackBag =
10)
{
m_isSerevr = m_pIsAsServer;
m_iBackBag = m_pIBackBag;
m_ipAddress = m_pHostAddrss;
m_port = m_pHostPort;
m_id = Guid.NewGuid().ToString();
}
///
<summary>
///
构造函数,用于服务器构造与客户端的异步socket
///
</summary>
///
<param name="LinkObject">
客户端socket
</param>
private AsyncSocket(Socket linkObject)
{
m_socket = linkObject;
m_id = Guid.NewGuid().ToString();
}
#endregion
#region 公共方法
///
<summary>
///
打开通道
///
</summary>
public
void AsyncOpen()
{
if (m_isSerevr)
{
IPAddress ip = Dns.GetHostAddresses(m_ipAddress)[
0];
IPEndPoint ipe =
new IPEndPoint(ip, m_port);
m_socket =
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_socket.Bind(ipe);
m_socket.Listen(m_iBackBag);
m_socket.BeginAccept(
new AsyncCallback(AcceptCallBack),
null);
//
异步
}
else
{
IPAddress ip = Dns.GetHostAddresses(m_ipAddress)[
0];
IPEndPoint ipe =
new IPEndPoint(ip, m_port);
m_socket =
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_socket.Connect(ipe);
}
}
///
<summary>
///
发送二进制数据
///
</summary>
///
<param name="SendData"></param>
public
void AsyncSend(
byte[] SendData)
{
m_socket.BeginSend(SendData,
0, SendData.Length,
0,
new AsyncCallback(SendCallBack), m_socket);
}
///
<summary>
///
关闭通道
///
</summary>
public
void AsyncClose()
{
if (!m_isSerevr)
{
m_socket.Shutdown(SocketShutdown.Both);
//
关闭接收发送流
m_socket.BeginDisconnect(
false, CloseCallBack, m_socket);
//
开始尝试断开
}
else
{
m_socket.Shutdown(SocketShutdown.Both);
//
关闭接收发送流
Thread.Sleep(
200);
//
等待现有任务处理完成
m_socket.Dispose();
//
释放所有本地资源
}
}
///
<summary>
///
开始接受数据,连接建立之后,调用此方法
///
</summary>
public
void BeginAcceptData()
{
//
开始接收数据
StateObject state =
new StateObject();
state.workSocket = m_socket;
m_socket.BeginReceive(state.buffer,
0, StateObject.BufferSize,
0,
new AsyncCallback(ReceiveCallback), state);
}
#endregion
#region 私有方法 成员
#endregion
#region 回调函数 成员
///
<summary>
///
接受客户端连接处理
///
</summary>
///
<param name="ar"></param>
private
void AcceptCallBack(IAsyncResult ar)
{
Socket handler = m_socket.EndAccept(ar);
AsyncSocket NewSocket =
new AsyncSocket(handler);
//
激发事件,异步触发
if (m_onAsyncSocketAcceptEvent !=
null)
foreach (AsyncSocketAcceptEventHandler item
in m_onAsyncSocketAcceptEvent.GetInvocationList())
item.BeginInvoke(NewSocket,
null,
null);
//
继续投递监听请求
m_socket.BeginAccept(
new AsyncCallback(AcceptCallBack),
null);
}
///
<summary>
///
接受字节流处理
///
</summary>
///
<param name="ar"></param>
private
void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject state = ar.AsyncState
as StateObject;
//
读取数据
int bytesRead = m_socket.EndReceive(ar);
if (bytesRead >
0)
{
byte[] _Readbyte =
new
byte[bytesRead];
Array.Copy(state.buffer,
0, _Readbyte,
0, bytesRead);
//
接收完成,激发事件
if (m_onAsyncDataAcceptedEvent !=
null)
foreach (AsyncDataAcceptedEventHandler item
in m_onAsyncDataAcceptedEvent.GetInvocationList())
item.BeginInvoke(
this, _Readbyte,
null,
null);
state =
new StateObject();
//
继续投递接收委托
state.workSocket = m_socket;
m_socket.BeginReceive(state.buffer,
0, StateObject.BufferSize,
0,
new AsyncCallback(ReceiveCallback), state);
}
}
catch (SocketException)
{
if (m_onAsyncSocketClosedEvent !=
null)
foreach (AsyncSocketClosedEventHandler item
in m_onAsyncSocketClosedEvent.GetInvocationList())
item.BeginInvoke(
this,
null,
null);
}
}
///
<summary>
///
发送结束处理
///
</summary>
///
<param name="ar"></param>
private
void SendCallBack(IAsyncResult ar)
{
try
{
m_socket.EndSend(ar);
if (m_onAsyncDataSendedEvent !=
null)
foreach (AsyncDataSendedEventHandler item
in m_onAsyncDataSendedEvent.GetInvocationList())
item.BeginInvoke(
this,
true,
null,
null);
}
catch (SocketException)
{
if (m_onAsyncDataSendedEvent !=
null)
foreach (AsyncDataSendedEventHandler item
in m_onAsyncDataSendedEvent.GetInvocationList())
item.BeginInvoke(
this,
false,
null,
null);
if (m_onAsyncSocketClosedEvent !=
null)
foreach (AsyncSocketClosedEventHandler item
in m_onAsyncSocketClosedEvent.GetInvocationList())
item.BeginInvoke(
this,
null,
null);
}
}
///
<summary>
///
关闭后处理
///
</summary>
///
<param name="ar"></param>
private
void CloseCallBack(IAsyncResult ar)
{
try
{
m_socket.EndDisconnect(ar);
m_socket.Dispose();
if (m_onAsyncDataSendedEvent !=
null)
foreach (AsyncSocketClosedEventHandler item
in m_onAsyncSocketClosedEvent.GetInvocationList())
item.BeginInvoke(
this,
null,
null);
}
catch (SocketException)
{
if (m_onAsyncSocketClosedEvent !=
null)
foreach (AsyncSocketClosedEventHandler item
in m_onAsyncSocketClosedEvent.GetInvocationList())
item.BeginInvoke(
this,
null,
null);
}
}
#endregion
}
}
代码注释还是蛮详细的,相信你看了也没什么不懂的地方。唯一让我不爽的是我异步事件不得不
foreach (AsyncSocketAcceptEventHandler item in m_onAsyncSocketAcceptEvent.GetInvocationList())
item.BeginInvoke(NewSocket, null, null);
这样的写法,很蛋疼。也试验了
Action asyncAction = () => m_onAsyncSocketAcceptEvent ();
asyncAction.BeginInvoke(
null ,
null
);
但郁闷的发现其实action虽然异步了,但那些事件还是顺序触发的,根本不是并发触发。无奈还是写那个蛋疼的foreach语句。顺便提到一句那个foreach中类型写全了,别用var,因为var会自动推断为Delegate。当然你自己再转换下也行,如果你喜欢的话。
我把代码贴出来的目的是找bug,还望各位大神多多指出其中问题。各种都可以,包括性能方面的。(我现在最怀疑的就是这里面到处异步,用线程池的资源会不会出现性能问题,毕竟线程有时候就是坑爹的)