天天看點

C# TCP用戶端 幫助類

初學C#,因為項目需要寫的一個理論上不會斷幀Tcp幫助類

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net.Sockets;

using System.Text;

using System.Threading;

using System.Windows;

namespace FM000023.Helper

{

class TcpHelper

{

private string ip;

private int port;

//聲明委托
    public delegate void DateReceiveDelegate(TcpHelper sender,byte[] data);
    public delegate void ConnectDelegate(TcpHelper sender);
    public delegate void SendDelegate(SendResult sendResult);

    /// <summary>
    /// 資料接收事件
    /// </summary>
    public event DateReceiveDelegate DataReceive;
    /// <summary>
    /// 連接配接成功事件
    /// </summary>
    public event ConnectDelegate ConnectSuccess;
    /// <summary>
    /// 連接配接失敗事件
    /// </summary>
    public event ConnectDelegate ConnectFailed;
    /// <summary>
    /// 發送成功完成事件
    /// </summary>
    public event SendDelegate SendDone;
    /// <summary>
    /// 循環讀取序列槽資料線程
    /// </summary>
    private Thread readSpDataThread;

    /// <summary>
    /// 工具類識别辨別
    /// </summary>
    public string name = "";

    private TcpClient tcpClient = new TcpClient();
    /// <summary>
    /// 構造函數
    /// </summary>
    /// <param name="ip">ip</param>
    /// <param name="port">port</param>
    public TcpHelper(string ip,int port)
    {
        this.ip = ip;
        this.port = port;
       tcpClient.BeginConnect(ip, port,new AsyncCallback(connectDone),tcpClient);

    }

    /// <summary>
    /// 連接配接完成
    /// </summary>
    /// <param name="ar"></param>
    private void connectDone(IAsyncResult ar)
    {
        try
        {
            tcpClient = (TcpClient)ar.AsyncState;
            tcpClient.EndConnect(ar);
            if (tcpClient != null && tcpClient.Connected)
            {
                if(ConnectSuccess != null)
                    Application.Current.Dispatcher.Invoke(ConnectSuccess,this);
                tcpClient.ReceiveTimeout = 30;
                tcpClient.SendTimeout = 1000;

                startReadDataOnNewThread();
            }
            else
            {
                if(ConnectFailed != null)
                    Application.Current.Dispatcher.Invoke(ConnectFailed,this);
            }
        }
        catch(Exception e)
        {
            if (ConnectFailed != null)
                Application.Current.Dispatcher.Invoke(ConnectFailed,this);
        }
    }

    /// <summary>
    /// 讀取資料
    /// </summary>
    private void startReadDataOnNewThread()
    {
        readSpDataThread = new Thread(readData);

        readSpDataThread.IsBackground = true;
        readSpDataThread.Start();
    }

    /// <summary>
    /// 讀取資料方法
    /// </summary>
    private void readData()
    {
        while(tcpClient.Connected)
        {
            NetworkStream ns = tcpClient.GetStream();
            if (ns.CanRead)
            {
                byte[] data = new byte[tcpClient.Available];
                int readLength = 0;
                try
                {
                   readLength =  ns.Read(data, 0, data.Length);
                    if (readLength > 0)
                    {
                        data = data.Take(readLength).ToArray();
                        DataReceive(this, data);
                    }
                }
                catch (Exception e)
                {
                    if(readLength > 0)
                    {
                        data = data.Take(readLength).ToArray();
                        DataReceive(this, data);
                    }
                }
                
            }
        }
    }

    /// <summary>
    /// 發送資料
    /// </summary>
    /// <param name="data">資料</param>
    public void sendData(byte[] data)
    {
        if(tcpClient != null && tcpClient.Connected)
        {
            NetworkStream ns = tcpClient.GetStream();
            if (ns.CanWrite)
            {
                WriteStateObject wso = new WriteStateObject();
                wso.ns = ns;
                wso.sendCmd = data;
                ns.BeginWrite(data, 0, data.Length, new AsyncCallback(sendDataDone), wso);
            }
            else
            {
                SendResult sendResult = new SendResult();
                sendResult.sender = this;
                sendResult.isSuccess = false;
                sendResult.reason = "NetworkStream不可寫";
                sendResult.sendCmd = data;
                SendDone(sendResult);
            }
        }
        else
        {
            SendResult sendResult = new SendResult();
            sendResult.sender = this;
            sendResult.isSuccess = false;
            sendResult.reason = "TcpClient為空或者TcpClient已經斷開連接配接";
            sendResult.sendCmd = data;
            SendDone(sendResult);
        }
    }

    /// <summary>
    /// 發送資料完成方法
    /// </summary>
    /// <param name="ar"></param>
    private void sendDataDone(IAsyncResult ar)
    {
        WriteStateObject wso = (WriteStateObject)ar.AsyncState;
        try
        {
            wso.ns.EndWrite(ar);
            SendResult sendResult = new SendResult();
            sendResult.sender = this;
            sendResult.isSuccess = true;
            sendResult.sendCmd = wso.sendCmd;
            SendDone(sendResult);
        }
        catch(Exception e)
        {
            SendResult sendResult = new SendResult();
            sendResult.sender = this;
            sendResult.isSuccess = false;
            sendResult.reason = e.ToString();
            sendResult.sendCmd = wso.sendCmd;
            SendDone(sendResult);
        }
        
    }

    /// <summary>
    /// 重新連接配接
    /// </summary>
    /// <param name="ip">ip</param>
    /// <param name="port">端口</param>
    public void reConnect(string ip = "",int port = 0)
    {
        tcpClient.Close();
        tcpClient = new TcpClient();
        if (ip == "")
            ip = this.ip;
        if (port == 0)
            port = this.port;
        tcpClient.BeginConnect(ip, port, new AsyncCallback(connectDone), tcpClient);
    }

    /// <summary>
    /// 檢查是否連接配接
    /// </summary>
    /// <returns></returns>
    public bool isConnected()
    {
        return tcpClient != null && tcpClient.Client != null && tcpClient.Connected;
    }

    /// <summary>
    /// 銷毀
    /// </summary>
    public void destoryHelper()
    {
        if(readSpDataThread != null)
            readSpDataThread.Abort();
        if(tcpClient != null)
            tcpClient.Close();
    }

    /// <summary>
    /// 發送結果實體類
    /// </summary>
    public class SendResult
    {
        /// <summary>
        /// 發送者
        /// </summary>
        public TcpHelper sender { set; get; }
        /// <summary>
        /// 發送的指令
        /// </summary>
        public byte[] sendCmd { set; get; }
        /// <summary>
        /// 發送是否成功
        /// </summary>
        public bool isSuccess { set; get; }
        /// <summary>
        /// 發送失敗原因
        /// </summary>
        public string reason { set; get; }
    }

    /// <summary>
    /// 發送資料的實體類
    /// </summary>
    private class WriteStateObject
    {
        /// <summary>
        /// 輸入輸出流
        /// </summary>
        public NetworkStream ns { set; get; }
        /// <summary>
        /// 發送的指令
        /// </summary>
        public byte[] sendCmd { set; get; }
    }

    /// <summary>
    /// 位元組數組轉十六進制字元串
    /// </summary>
    /// <param name="data">位元組數組</param>
    /// <returns>傳回十六進制字元串</returns>
    public static string byteToHexString(byte[] data)
    {
        string dataStr = "";
        foreach (byte b in data)
        {
            dataStr += b.ToString("X2");
        }

        return dataStr;
    }

    /// <summary>
    /// 十六進制字元串轉位元組數組
    /// </summary>
    /// <param name="data">十六進制字元串</param>
    /// <returns>位元組數組</returns>
    public static byte[] hexStringToByte(string data)
    {
        if (data.Count() % 2 != 0)
            return null;
        byte[] dataByte = new byte[data.Count() / 2];
        for (int i = 0, j = 0; i < data.Count(); i += 2, j++)
        {
            dataByte[j] = (byte)Convert.ToInt32(data.Substring(i, 2), 16);
        }

        return dataByte;
    }

    /// <summary>
    /// 計算校驗和
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static int calcSum(byte[] data)
    {
        return 0xFF & data.Select(x => (int)x).Sum() % 256;
    }
}
           

}