首页 > 代码库 > GJM : Socket TCP 通信连接(二)

GJM : Socket TCP 通信连接(二)

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

这一篇将讲解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 =http://www.mamicode.com/= null)"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 = http://www.mamicode.com/data;"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 = http://www.mamicode.com/new byte[2];"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的功能已经实现。

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

 

GJM : Socket TCP 通信连接(二)