[C#]手把手教你打造Socket的TCP通讯连接(二)

来源:互联网 发布:c语言中数据类型长度 编辑:程序博客网 时间:2024/06/06 16:30

上一篇中,我们编写了客户端功能。

这一篇将讲解ISocketHandler的实现。

再来回顾一下ISocketHandler接口。

public interface ISocketHandler{    /// <summary>    /// 开始接收    /// </summary>    /// <param name="stream">Socket网络流</param>    /// <param name="callback">回调函数</param>    /// <param name="state">自定义状态</param>    /// <returns>异步结果</returns>    IAsyncResult BeginReceive(Stream stream, AsyncCallback callback, object state);    /// <summary>    /// 结束接收    /// </summary>    /// <param name="asyncResult">异步结果</param>    /// <returns>接收到的数据</returns>    byte[] EndReceive(IAsyncResult asyncResult);    /// <summary>    /// 开始发送    /// </summary>    /// <param name="data">要发送的数据</param>    /// <param name="offset">数据偏移</param>    /// <param name="count">发送长度</param>    /// <param name="stream">Socket网络流</param>    /// <param name="callback">回调函数</param>    /// <param name="state">自定义状态</param>    /// <returns>异步结果</returns>    IAsyncResult BeginSend(byte[] data, int offset, int count, Stream stream, AsyncCallback callback, object state);    /// <summary>    /// 结束发送    /// </summary>    /// <param name="asyncResult">异步结果</param>    /// <returns>发送是否成功</returns>    bool EndSend(IAsyncResult asyncResult);}

做一个类SocketHandler继承ISocketHandler接口

/// <summary>/// Socket处理程序/// </summary>public class SocketHandler : ISocketHandler{    /// <summary>    /// 开始接收    /// </summary>    /// <param name="stream">Socket网络流</param>    /// <param name="callback">回调函数</param>    /// <param name="state">自定义状态</param>    /// <returns>异步结果</returns>    public IAsyncResult BeginReceive(Stream stream, AsyncCallback callback, object state)    {    }    /// <summary>    /// 结束接收    /// </summary>    /// <param name="asyncResult">异步结果</param>    /// <returns>接收到的数据</returns>    public byte[] EndReceive(IAsyncResult asyncResult)    {    }    /// <summary>    /// 开始发送    /// </summary>    /// <param name="data">要发送的数据</param>    /// <param name="offset">数据偏移</param>    /// <param name="count">发送长度</param>    /// <param name="stream">Socket网络流</param>    /// <param name="callback">回调函数</param>    /// <param name="state">自定义状态</param>    /// <returns>异步结果</returns>    public IAsyncResult BeginSend(byte[] data, int offset, int count, Stream stream, AsyncCallback callback, object state)    {    }    /// <summary>    /// 结束发送    /// </summary>    /// <param name="asyncResult">异步结果</param>    /// <returns>发送是否成功</returns>    public bool EndSend(IAsyncResult asyncResult)    {    }}

增加两个属性与构造函数。

    //异步处理关系集合    private Dictionary<IAsyncResult, SocketHandlerState> StateSet;    //发送队列    private List<SocketHandlerState> SendQueue;    /// <summary>    /// 实例化Socket处理程序    /// </summary>    public SocketHandler()    {        StateSet = new Dictionary<IAsyncResult, SocketHandlerState>();        SendQueue = new List<SocketHandlerState>();    }

StateSet可以保存我们的异步调用结果等数据

SendQueue用来做一个发送队列

接下来我们从发送数据开始。

由于需要用到Stream的异步方法,我们需要定义一个State类。

internal class SocketHandlerState{    /// <summary>    /// 数据    /// </summary>    public byte[] Data { get; set; }    /// <summary>    /// 异步结果    /// </summary>    public IAsyncResult AsyncResult { get; set; }    /// <summary>    /// Socket网络流    /// </summary>    public Stream Stream { get; set; }    /// <summary>    /// 异步回调函数    /// </summary>    public AsyncCallback AsyncCallBack { get; set; }    /// <summary>    /// 是否完成    /// </summary>    public bool Completed { get; set; }    /// <summary>    /// 数据长度    /// </summary>    public int DataLength { get; set; }}

因为我们需要返回IAsyncResult,所以我们继承该接口做一个SocketHandlerState类。

/// <summary>/// Socket异步操作状态/// </summary>public class SocketAsyncResult : IAsyncResult{    /// <summary>    /// 实例化Socket异步操作状态    /// </summary>    /// <param name="state"></param>    public SocketAsyncResult(object state)    {        AsyncState = state;        AsyncWaitHandle = new AutoResetEvent(false);    }    /// <summary>    /// 获取用户定义的对象,它限定或包含关于异步操作的信息。    /// </summary>    public object AsyncState { get; private set; }    /// <summary>    /// 获取用于等待异步操作完成的 System.Threading.WaitHandle。    /// </summary>    public WaitHandle AsyncWaitHandle { get; private set; }    /// <summary>    /// 获取一个值,该值指示异步操作是否同步完成。    /// </summary>    public bool CompletedSynchronously { get { return false; } }    /// <summary>    /// 获取一个值,该值指示异步操作是否已完成。    /// </summary>    public bool IsCompleted { get; internal set; }}

然后开始编写发送数据相关函数。

这里我将发送数据的大小限制为最大65535。

只需发送长度为2的头信息即可把数据长度发送到对方。

    /// <summary>    /// 开始发送    /// </summary>    /// <param name="data">要发送的数据</param>    /// <param name="offset">数据偏移</param>    /// <param name="count">发送长度</param>    /// <param name="stream">Socket网络流</param>    /// <param name="callback">回调函数</param>    /// <param name="state">自定义状态</param>    /// <returns>异步结果</returns>    public IAsyncResult BeginSend(byte[] data, int offset, int count, Stream stream, AsyncCallback callback, object state)    {        //data不能为null        if (data == null)            throw new ArgumentNullException("data");        //offset不能小于0和超过data长度        if (offset > data.Length || offset < 0)            throw new ArgumentOutOfRangeException("offset");        //count不能大于65535        if (count <= 0 || count > data.Length - offset || count > ushort.MaxValue)            throw new ArgumentOutOfRangeException("count");        //stream不能为null        if (stream == null)            throw new ArgumentNullException("stream");        //回调函数不能为null        if (callback == null)            throw new ArgumentNullException("callback");        //stream异常        if (!stream.CanWrite)            throw new ArgumentException("stream不支持写入。");        SocketAsyncResult result = new SocketAsyncResult(state);        //初始化SocketHandlerState        SocketHandlerState shs = new SocketHandlerState();        shs.Data = data;        shs.AsyncResult = result;        shs.Stream = stream;        shs.AsyncCallBack = callback;        shs.DataLength = 0;        //锁定SendQueue        //避免多线程同时发送数据        lock (SendQueue)        {            //添加状态            SendQueue.Add(shs);            //如果SendQueue数量大于1,则表示有数据尚未发送完成            if (SendQueue.Count > 1)                return result;        }        //获取数据长度        //ushort的最大值为65535        //转换为byte[]长度为2        var dataLength = BitConverter.GetBytes((ushort)data.Length);        //向对方发送长度为2的头信息,表示接下来要发送的数据长度        stream.Write(dataLength, 0, dataLength.Length);        //开始异步发送数据        stream.BeginWrite(shs.Data, 0, shs.Data.Length, EndWrite, shs).AsyncWaitHandle.WaitOne();        return result;    }    //stream异步结束写入    private void EndWrite(IAsyncResult ar)    {        SocketHandlerState state = (SocketHandlerState)ar.AsyncState;        //锁定StateSet        lock (StateSet)            StateSet.Add(state.AsyncResult, state);        try        {            state.Stream.EndWrite(ar);        }        catch        {            //出现Socket异常,发送失败            state.Completed = false;            //允许等待线程继续            ((AutoResetEvent)state.AsyncResult.AsyncWaitHandle).Set();            //执行异步回调函数            state.AsyncCallBack(state.AsyncResult);            return;        }        //发送成功        state.Completed = true;        //允许等待线程继续        ((AutoResetEvent)state.AsyncResult.AsyncWaitHandle).Set();        //执行异步回调函数        state.AsyncCallBack(state.AsyncResult);        //锁定SendQueue        lock (SendQueue)        {            SocketHandlerState prepare = null;            //移除当前发送完成的数据            SendQueue.Remove(state);            //如果SendQueue还有数据存在,则继续发送            if (SendQueue.Count > 0)            {                prepare = SendQueue[0];            }            if (prepare != null)            {                //获取数据长度                //ushort的最大值为65535                //转换为byte[]长度为2                var dataLength = BitConverter.GetBytes((ushort)prepare.Data.Length);                //向对方发送长度为2的头信息,表示接下来要发送的数据长度                prepare.Stream.Write(dataLength, 0, dataLength.Length);                //开始异步发送数据                prepare.Stream.BeginWrite(prepare.Data, 0, prepare.Data.Length, EndWrite, prepare).AsyncWaitHandle.WaitOne();            }        }    }    /// <summary>    /// 结束发送    /// </summary>    /// <param name="asyncResult">异步结果</param>    /// <returns>发送是否成功</returns>    public bool EndSend(IAsyncResult asyncResult)    {        //判断异步操作状态是否属于当前处理程序        if (!StateSet.ContainsKey(asyncResult))            throw new ArgumentException("无法识别的asyncResult。");        SocketHandlerState state = StateSet[asyncResult];        lock (StateSet)            StateSet.Remove(asyncResult);        return state.Completed;    }

接下来是接收数据的相关方法。

    /// <summary>    /// 开始接收    /// </summary>    /// <param name="stream">Socket网络流</param>    /// <param name="callback">回调函数</param>    /// <param name="state">自定义状态</param>    /// <returns>异步结果</returns>    public IAsyncResult BeginReceive(Stream stream, AsyncCallback callback, object state)    {        //stream不能为null        if (stream == null)            throw new ArgumentNullException("stream");        //回调函数不能为null        if (callback == null)            throw new ArgumentNullException("callback");        //stream异常        if (!stream.CanRead)            throw new ArgumentException("stream不支持读取。");        SocketAsyncResult result = new SocketAsyncResult(state);        //初始化SocketHandlerState        SocketHandlerState shs = new SocketHandlerState();        shs.Data = new byte[2];        shs.AsyncResult = result;        shs.Stream = stream;        shs.AsyncCallBack = callback;        shs.Completed = true;        //开始异步接收长度为2的头信息        //该头信息包含要接收的主要数据长度        stream.BeginRead(shs.Data, 0, 2, EndRead, shs);        return result;    }    //stream异步结束读取    private void EndRead(IAsyncResult ar)    {        SocketHandlerState state = (SocketHandlerState)ar.AsyncState;        int dataLength;        try        {            dataLength = state.Stream.EndRead(ar);        }        catch        {            dataLength = 0;        }        //dataLength为0则表示Socket断开连接        if (dataLength == 0)        {            lock (StateSet)                StateSet.Add(state.AsyncResult, state);            //设定接收到的数据位空byte数组            state.Data = new byte[0];            //允许等待线程继续            ((AutoResetEvent)state.AsyncResult.AsyncWaitHandle).Set();            //执行异步回调函数            state.AsyncCallBack(state.AsyncResult);            return;        }        //如果是已完成状态,则表示state.Data的数据是头信息        if (state.Completed)        {            //设定状态为未完成            state.Completed = false;            //已接收得数据长度为0            state.DataLength = 0;            //获取主要数据长度            var length = BitConverter.ToUInt16(state.Data, 0);            //初始化数据的byte数组            state.Data = new byte[length];            try            {                //开始异步接收主要数据                state.Stream.BeginRead(state.Data, 0, length, EndRead, state);            }            catch            {                //出现Socket异常                lock (StateSet)                    StateSet.Add(state.AsyncResult, state);                state.Data = new byte[0];                ((AutoResetEvent)state.AsyncResult.AsyncWaitHandle).Set();                state.AsyncCallBack(state.AsyncResult);            }            return;        }        //接收到主要数据        else        {            //判断是否接收了完整的数据            if (dataLength + state.DataLength != state.Data.Length)            {                //增加已接收数据长度                state.DataLength += dataLength;                try                {                    //继续接收数据                    state.Stream.BeginRead(state.Data, state.DataLength, state.Data.Length - state.DataLength, EndRead, state);                }                catch                {                    //出现Socket异常                    lock (StateSet)                        StateSet.Add(state.AsyncResult, state);                    state.Data = new byte[0];                    ((AutoResetEvent)state.AsyncResult.AsyncWaitHandle).Set();                    state.AsyncCallBack(state.AsyncResult);                    return;                }                return;            }            //接收完成            state.Completed = true;            lock (StateSet)                StateSet.Add(state.AsyncResult, state);            ((AutoResetEvent)state.AsyncResult.AsyncWaitHandle).Set();            state.AsyncCallBack(state.AsyncResult);        }    }    /// <summary>    /// 结束接收    /// </summary>    /// <param name="asyncResult">异步结果</param>    /// <returns>接收到的数据</returns>    public byte[] EndReceive(IAsyncResult asyncResult)    {        //判断异步操作状态是否属于当前处理程序        if (!StateSet.ContainsKey(asyncResult))            throw new ArgumentException("无法识别的asyncResult。");        SocketHandlerState state = StateSet[asyncResult];        lock (StateSet)            StateSet.Remove(asyncResult);        return state.Data;    }

至此,SocketHandler的功能已经实现。

下一篇将为大家讲解服务器端的实现。

 

原文地址:http://www.cnblogs.com/Kation/archive/2013/03/06/2947145.html


<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* cnblogs 首页横幅 */google_ad_slot = "5419468456";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
原创粉丝点击