五维思考

学习要加,骄傲要减,机会要乘,懒惰要除。 http://www.5dthink.cn

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

看了系列一 我们开启了对socket tcp的监听状态,那么这一章我们来讲解怎么创建socket的通信代码

我新建一个类 TSocketBase

public abstract class TSocketBase
{
    //封装socket
    internal Socket _Socket;
    //回调
    private AsyncCallback aCallback;
    //接受数据的缓冲区
    private byte[] Buffers;
    //标识是否已经释放
    private volatile bool IsDispose;
    //10K的缓冲区空间
    private int BufferSize = 10*1024;
    //收取消息状态码
    private SocketError ReceiveError;
    //发送消息的状态码
    private SocketError SenderError;
    //每一次接受到的字节数
    private int ReceiveSize = 0;
    //接受空消息次数
    private byte ZeroCount = 0;

    public abstract void Receive(byte[] rbuff);

    public void SetSocket()
    {
        this.aCallback = new AsyncCallback(this.ReceiveCallback);
        this.IsDispose = false;
        this._Socket.ReceiveBufferSize = this.BufferSize;
        this._Socket.SendBufferSize = this.BufferSize;
        this.Buffers = new byte[this.BufferSize];
    }


    /// <summary>
    /// 关闭并释放资源
    /// </summary>
    /// <param name="msg"></param>
    public void Close(string msg)
    {
        if (!this.IsDispose)
        {
            this.IsDispose = true;
            try
            {
                try
                {
                    this._Socket.Close();
                }
                catch
                {
                }
                IDisposable disposable = this._Socket;
                if (disposable != null)
                {
                    disposable.Dispose();
                }
                this.Buffers = null;
                GC.SuppressFinalize(this);
            }
            catch (Exception)
            {
            }
        }
    }


    /// <summary>
    /// 递归接收消息方法
    /// </summary>
    internal void ReceiveAsync()
    {
        try
        {
            if (!this.IsDispose && this._Socket.Connected)
            {
                this._Socket.BeginReceive(this.Buffers, 0, this.BufferSize, SocketFlags.None, out SenderError,
                    this.aCallback, this);
                CheckSocketError(ReceiveError);
            }
        }
        catch (System.Net.Sockets.SocketException)
        {
            this.Close("链接已经被关闭");
        }
        catch (System.ObjectDisposedException)
        {
            this.Close("链接已经被关闭");
        }
    }


    /// <summary>
    /// 接收消息回调函数
    /// </summary>
    /// <param name="iar"></param>
    private void ReceiveCallback(IAsyncResult iar)
    {
        if (!this.IsDispose)
        {
            try
            {
                //接受消息
                ReceiveSize = _Socket.EndReceive(iar, out ReceiveError);
                //检查状态码
                if (!CheckSocketError(ReceiveError) && SocketError.Success == ReceiveError)
                {
                    //判断接受的字节数
                    if (ReceiveSize > 0)
                    {
                        byte[] rbuff = new byte[ReceiveSize];
                        Array.Copy(this.Buffers, rbuff, ReceiveSize);
                        this.Receive(rbuff);
                        //重置连续收到空字节数
                        ZeroCount = 0;
                        //继续开始异步接受消息
                        ReceiveAsync();
                    }
                    else
                    {
                        ZeroCount++;
                        if (ZeroCount == 5)
                        {
                            this.Close("错误链接");
                        }
                    }
                }
            }
            catch (System.Net.Sockets.SocketException)
            {
                this.Close("链接已经被关闭");
            }
            catch (System.ObjectDisposedException)
            {
                this.Close("链接已经被关闭");
            }
        }
    }

    /// <summary>
    /// 错误判断
    /// </summary>
    /// <param name="socketError"></param>
    /// <returns></returns>
    private bool CheckSocketError(SocketError socketError)
    {
        switch ((socketError))
        {
            case SocketError.SocketError:
            case SocketError.VersionNotSupported:
            case SocketError.TryAgain:
            case SocketError.ProtocolFamilyNotSupported:
            case SocketError.ConnectionAborted:
            case SocketError.ConnectionRefused:
            case SocketError.ConnectionReset:
            case SocketError.Disconnecting:
            case SocketError.HostDown:
            case SocketError.HostNotFound:
            case SocketError.HostUnreachable:
            case SocketError.NetworkDown:
            case SocketError.NetworkReset:
            case SocketError.NetworkUnreachable:
            case SocketError.NoData:
            case SocketError.OperationAborted:
            case SocketError.Shutdown:
            case SocketError.SystemNotReady:
            case SocketError.TooManyOpenSockets:
                this.Close(socketError.ToString());
                return true;
        }
        return false;
    }

    /// <summary>
    /// 发送消息方法
    /// </summary>
    internal int SendMsg(byte[] buffer)
    {
        int size = 0;
        try
        {
            if (!this.IsDispose)
            {
                size = this._Socket.Send(buffer, 0, buffer.Length, SocketFlags.None, out SenderError);
                CheckSocketError(SenderError);
            }
        }
        catch (System.ObjectDisposedException)
        {
            this.Close("链接已经被关闭");
        }
        catch (System.Net.Sockets.SocketException)
        {
            this.Close("链接已经被关闭");
        }
        buffer = null;
        return size;
    }
}

上面我们事先了socket的异步接受消息,和同步发送消息已经关闭释放资源代码

接受消息net底层提供的接受消息的方法有很多,为什么我们要选择上面所写的呢?那是为了兼容U3D,silverlight, wpf, wp, wf,等程序可执行,不在重复做相同工作。

现在我们来创建一个实现类 TSocketClient

public class TSocketClient : TSocketBase
{
    /// <summary>
    /// 是否是服务器端的资源
    /// </summary>
    private bool isServer = false;

    /// <summary>
    /// 客户端主动请求服务器
    /// </summary>
    /// <param name="ip"></param>
    /// <param name="port"></param>
    public TSocketClient(string ip = "127.0.0.1", int port = 9527)
    {
        isServer = false;
        this._Socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        this._Socket.Connect(ip, port);
        this.SetSocket();
        this.ReceiveAsync();
    }

    /// <summary>
    /// 这个是服务器收到有效链接初始化
    /// </summary>
    /// <param name="socket"></param>
    public TSocketClient(Socket socket)
    {
        isServer = true;
        this._Socket = socket;
        this.SetSocket();
        this.ReceiveAsync();
    }

    /// <summary>
    /// 收到消息后
    /// </summary>
    /// <param name="rbuff"></param>
    public override void Receive(byte[] rbuff)
    {
        Console.WriteLine("Receive Msg:" + System.Text.UTF8Encoding.Default.GetString(rbuff));
        if (isServer)
        {
            this.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Client!"));
        }
    }
}

因为是测试示例,所以我把服务器和客户端实现类写成了,只是用来不同的构造函数来区分,是客户端还是服务器的标识 

接下来我们测试一下代码

class Program
{
    static void Main(string[] args)
    {
        TCPListener tcp = new TCPListener();
        TSocketClient client = new TSocketClient();
        client.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Server!"));
        Console.ReadLine();
    }
}

 

 

运行结果看出,我们连接成功并且发送消息成功。

posted on 2019-06-19 10:23  五维思考  阅读(1578)  评论(0编辑  收藏  举报

QQ群:1. 全栈码农【346906288】2. VBA/VSTO【2660245】