c# Socket(客户端)异步通讯

        实现功能,能够随时发送数据,并且能够随时接收服务端发送过来的数据,能够判断服务端或端口网络的连接状态,随时查看与服务器通讯是否通畅。

        可以使用VS创建一个用户控件或创建一个类,来控制Socket通讯,代码成熟,建议做成用户控件,这样可以随时拖拽控件,写事件什么的都方便。

        在写Socket客户端之前,要知道Socket客户端接收数据,使用 的线程循环的方式,有数据接收到的时候,触发消息事件,在断开事件处理时,能够触发断开连接事件,这时要定义几个委托,承载事件的触发。

        public delegate void ReceiveBuffer(byte[] buffer);//收到消息时,传递消息Buffer的事件。

        public delegate void HostDisconnectionEvent();//断开连接时,触发的事件。

        我在使用的时候,习惯将委托单独放在一个.cs文件当,定义为委托事件类:DelegateEvent.cs

        还要考虑到,在Socket接收消息时,需要使用线程,那么在触发收到消息的事件后,如果需要修改界面上的参数或值,需要做控件的异步调用处理,这样处理起来太麻烦,而且处理不好,到时会有一堆的Bug,这是我在使用过程当中遇到的。那么有一没有办法不使用线程,让客户端循环接收消息呢?这时我想到了使用异步,最后又增加了一个异步收消息的委托:

        public delegate void AsyncReceivedClient(object sender);//异步收到消息时的委托,如果整个类当中只有一个客户端连接,可以不带参数。

        这时,委托类基本建完了,那么,这时需要定义代码了:

    创建一个TCPClient类,当然,这个类和System.Net.Sockets下的类不同,为了区分,我定义的命名空间为:System.Net.Securate.TCP,下面是定义的事件和参数:

        /// <summary>
        /// 收到消息事件
        /// </summary>
        public ReceiveBuffer ReceiveComtemplate;
        /// <summary>
        /// 主机断开连接事件
        /// </summary>
        public HostDisconnectionEvent HostDisconnectedComtelplate;
        private string _Address;
        /// <summary>
        /// 获取或设置连接地址
        /// </summary>
        public string Address
        {
            get { return _Address; }
            set { _Address = value; }
        }
        private int _Port;
        /// <summary>
        /// 获取或设置端口号
        /// </summary>
        public int Port
        {
            get { return _Port; }
            set { _Port = value; }
        }
        private Socket tcpClient;
        /// <summary>
        /// 获取连接状态
        /// </summary>
        public bool IsConnected
        {
            get {
                if (tcpClient == null)
                    return false;
                return tcpClient.Connected;
            }
        }

        创建连接的启动事件,我写两种启动方式,一种是不带参的,一种是带参的,如下:

        /// <summary>
        /// 打开连接
        /// </summary>
        /// <returns></returns>
        public bool Start()
        {
            return Start(_Address, _Port);
        }
        /// <summary>
        /// 打开连接
        /// </summary>
        /// <param name="ip">连接地址</param>
        /// <param name="port">连接端口号</param>
        /// <returns></returns>
        public bool Start(string ip, int port)
        {
            try
            {
                _Address = ip;
                _Port = port;
                tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ipaddress = IPAddress.Parse(_Address);
                tcpClient.Connect(ipaddress, port);
                if (tcpClient.Connected)
                {
                    AsyncReceivedClient rc = new AsyncReceivedClient(Receive);
                    rc.BeginInvoke(tcpClient, null, null);
                }
                return tcpClient.Connected;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        需要注意的是:

        AsyncReceivedClient rc = new AsyncReceivedClient(Receive);
        rc.BeginInvoke(tcpClient, null, null);

        这两行,实现的是异步委托带参的调用,实现随时接收服务端发送过来的消息。

      在客户端收消息时,需要判断服务端连接是否断开,在网上的介绍上,说使用socket.Poll(1, SelectMode.SelectRead)和socket.Available= 0来判断网络是否断开,但在实际上的使用当中,我使用第三方的服务端,使用这种方式,根本不能判断断开,后来我想,能不能开一个SocketCient,来判断服务端口是否正常,相当于telnet命令,在实际使用当中,还没遇到问题:

        /// <summary>
        /// 接收消息
        /// </summary>
        /// <returns></returns>
        public void Receive(object o)
        {
            Socket s = o as Socket;
            bool IsConnected = true;
            while (s.Connected)
            {
                try
                {
                    int res = s.Available;
                    if (res > 0)
                    {
                        byte[] xxxx = new byte[res];
                        int nRead = s.Receive(xxxx);
                        byte[] buffer = new byte[nRead];
                        Array.Copy(xxxx, 0, buffer, 0, nRead);
                        if (ReceiveComtemplate != null)
                            ReceiveComtemplate(buffer);
                    }
                    else
                    {
                        try
                        {
                            Socket testSocket =
                                new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                            testSocket.Connect(s.RemoteEndPoint);
                            if (!testSocket.Connected)
                            {
                                Stop();
                                IsConnected = false;
                                goto EndReceive;
                            }
                            else
                            {
                                testSocket.Shutdown(SocketShutdown.Both);
                                testSocket.Close();
                            }
                        }
                        catch (Exception ex)
                        {
                            Stop();
                            IsConnected = false;
                            goto EndReceive;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Stop();
                    IsConnected = false;
                    goto EndReceive;
                }
                Thread.Sleep(100);
            }
            EndReceive:
            if (!IsConnected)
            {
                if (HostDisconnectedComtelplate != null)
                    HostDisconnectedComtelplate();
            }
        }

        最后就是一个发送,一个停止,这个部分,基本和msdn上介绍的一样,没有什么特殊的处理:

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="buffer">发送的数据</param>
        public void Send(byte[] buffer)
        {
            try
            {
                if (tcpClient.Connected)
                {
                    tcpClient.Send(buffer);
                }
            }
            catch { }
        }
        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            try
            {
                //tcpClient.Client.Shutdown(SocketShutdown.Both);
                //tcpClient.Close();
                tcpClient.Shutdown(SocketShutdown.Both);
                tcpClient.Close();
            }
            catch (Exception ex)
            { }
        }

        到这里基本上已经完成,完整代码如下,如果有不同看法或有更好的意见,欢迎在线留言:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;

namespace System.Net.Securate.TCP
{
    public sealed class TCPClient
    {
        /// <summary>
        /// 收到消息事件
        /// </summary>
        public ReceiveBuffer ReceiveComtemplate;
        /// <summary>
        /// 主机断开连接事件
        /// </summary>
        public HostDisconnectionEvent HostDisconnectedComtelplate;
        private string _Address;
        /// <summary>
        /// 获取或设置连接地址
        /// </summary>
        public string Address
        {
            get { return _Address; }
            set { _Address = value; }
        }
        private int _Port;
        /// <summary>
        /// 获取或设置端口号
        /// </summary>
        public int Port
        {
            get { return _Port; }
            set { _Port = value; }
        }
        private Socket tcpClient;
        /// <summary>
        /// 获取连接状态
        /// </summary>
        public bool IsConnected
        {
            get {
                if (tcpClient == null)
                    return false;
                return tcpClient.Connected;
            }
        }
        /// <summary>
        /// 打开连接
        /// </summary>
        /// <returns></returns>
        public bool Start()
        {
            return Start(_Address, _Port);
        }
        /// <summary>
        /// 打开连接
        /// </summary>
        /// <param name="ip">连接地址</param>
        /// <param name="port">连接端口号</param>
        /// <returns></returns>
        public bool Start(string ip, int port)
        {
            try
            {
                _Address = ip;
                _Port = port;
                tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ipaddress = IPAddress.Parse(_Address);
                tcpClient.Connect(ipaddress, port);
                if (tcpClient.Connected)
                {
                    AsyncReceivedClient rc = new AsyncReceivedClient(Receive);
                    rc.BeginInvoke(tcpClient, null, null);
                }
                return tcpClient.Connected;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        /// <summary>
        /// 接收消息
        /// </summary>
        /// <returns></returns>
        public void Receive(object o)
        {
            Socket s = o as Socket;
            bool IsConnected = true;
            while (s.Connected)
            {
                try
                {
                    int res = s.Available;
                    if (res > 0)
                    {
                        byte[] xxxx = new byte[res];
                        int nRead = s.Receive(xxxx);
                        byte[] buffer = new byte[nRead];
                        Array.Copy(xxxx, 0, buffer, 0, nRead);
                        if (ReceiveComtemplate != null)
                            ReceiveComtemplate(buffer);
                    }
                    else
                    {
                        try
                        {
                            Socket testSocket =
                                new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                            testSocket.Connect(s.RemoteEndPoint);
                            if (!testSocket.Connected)
                            {
                                Stop();
                                IsConnected = false;
                                goto EndReceive;
                            }
                            else
                            {
                                testSocket.Shutdown(SocketShutdown.Both);
                                testSocket.Close();
                            }
                        }
                        catch (Exception ex)
                        {
                            Stop();
                            IsConnected = false;
                            goto EndReceive;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Stop();
                    IsConnected = false;
                    goto EndReceive;
                }
                Thread.Sleep(100);
            }
            EndReceive:
            if (!IsConnected)
            {
                if (HostDisconnectedComtelplate != null)
                    HostDisconnectedComtelplate();
            }
        }
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="buffer">发送的数据</param>
        public void Send(byte[] buffer)
        {
            try
            {
                if (tcpClient.Connected)
                {
                    tcpClient.Send(buffer);
                }
            }
            catch { }
        }
        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            try
            {
                //tcpClient.Client.Shutdown(SocketShutdown.Both);
                //tcpClient.Close();
                tcpClient.Shutdown(SocketShutdown.Both);
                tcpClient.Close();
            }
            catch (Exception ex)
            { }
        }
    }
}
 

猜你喜欢

转载自blog.csdn.net/luckystart0/article/details/82980078