天天看點

WinFormSocketTCP異步多線程實作斷線重連完整源碼附注釋

TCP最主要的特點如下。

(1) 是面向連接配接的協定。

(2) 端到端的通信。每個TCP連接配接隻能有兩個端點,而且隻能一對一通信,不能一點對多點直接通信。

(3) 高可靠性。通過TCP連接配接傳送的資料,能保證資料無差錯、不丢失、不重複地準确到達接收方,并且保證各資料到達的順序與其發出的順序相同

異步與同步的差別

同步工作方式是指利用TCP編寫的程式執行到監聽或接收語句時,在未完成工作(偵聽到連接配接請求或收到對方發來的資料)前不再繼續往下執行,線程處于阻塞狀态,直到該語句完成相應的工作後才繼續執行下一條語句。

異步工作方式是指程式執行到監聽或接收語句時,不論工作是否完成,都會繼續往下執行

完整源碼如下:

public partial class MainForm : Form
    {
        private Socket socket;
        //Thread threadConnect;
        private int sendCount = 0;
        private int receiveCount = 0;
        /*------------定義與聲明委托------------*/
        //顯示消息
        private delegate void ShowMsgCallBack(string str);
        private ShowMsgCallBack showMsgCallBack;
        //顯示狀态
        private delegate void ShowStatusInfoCallBack(string str);
        private ShowStatusInfoCallBack showStatusInfoCallBack;
        //顯示發送計數
        private delegate void ShowSendCountCallBack(string str);
        private ShowSendCountCallBack showSendCountCallBack;
        //顯示接收計數
        private delegate void ShowReceiveCountCallBack(string str);
        private ShowReceiveCountCallBack showReceiveCountCallBack;
        //定時重連
        private delegate void ReConnectCallBack();
        private ReConnectCallBack reConnectCallBack;
        //異步調用(與要調用的方法具有相同簽名)
        private delegate void ReceiveMsgDelegate(out string receiveMsg);
        private ReceiveMsgDelegate receiveMsgDelegate;
        private delegate void SendMsgDelegate(string sendMsg);
        private SendMsgDelegate sendMsgDelegate;
        /*------------定義與聲明委托------------*/
        public MainForm()
        {
            InitializeComponent();
            /*----------執行個體化委托----------*/
            //顯示消息
            showMsgCallBack = new ShowMsgCallBack(ShowMsg);
            //顯示狀态
            showStatusInfoCallBack = new ShowStatusInfoCallBack(ShowStatusInfo);
            //顯示發送計數
            showSendCountCallBack = new ShowSendCountCallBack(ShowSendCount);
            //顯示接收計數
            showReceiveCountCallBack = new ShowReceiveCountCallBack(ShowReceiveCount);
            //掉線後自動啟動定時重連
            reConnectCallBack = new ReConnectCallBack(ReConnect);
            //接收消息
            receiveMsgDelegate = new ReceiveMsgDelegate(AsyncRcvMsg);
            //發送消息
            sendMsgDelegate = new SendMsgDelegate(AsyncSendMsg);
            /*----------執行個體化委托----------*/
            IPAddress[] localIP = Dns.GetHostAddresses("");
            txtIP.Text = localIP[0].ToString();
            txtIP.SelectAll();
            txtPort.Text = "9501";
            tbxReceiveCount.Text = sendCount.ToString();
            tbxReceiveCount.Text = receiveCount.ToString();

            
        }

        /*----------定義回調函數----------*/
        //顯示消息
        private void ShowMsg(string str)
        {
            lstBoxMsg.Items.Add(str);
            lstBoxMsg.TopIndex = lstBoxMsg.Items.Count - 1;
        }

        //顯示狀态
        private void ShowStatusInfo(string str)
        {
            toolStripStatusInfo.Text = str;
        }

        //顯示發送計數
        private void ShowSendCount(string str)
        {
            tbxSendCount.Text = str;
        }

        //顯示接收計數
        private void ShowReceiveCount(string str)
        {
            tbxReceiveCount.Text = str;
        }

        private void ReConnect()
        {
            startConnectServer();
        }

        //異步接收
        private void AsyncRcvMsg(out string receiveMessage)
        {
            receiveMessage = null;
            try
            {
                Byte[] receiveByte = new Byte[64];
                socket.Receive(receiveByte, receiveByte.Length, 0);
                receiveMessage = Encoding.ASCII.GetString(receiveByte);
                if (receiveMessage.Trim('\0').Length == 0)
                {
                    if (socket != null)
                    {
                        socket.Close();
                    }
                    statusStripInfo.Invoke(showStatusInfoCallBack, "異步接收時連接配接斷開!延時10秒後自動重新連接配接...");
                    //延時10秒後重新連接配接
                    DateTime now = DateTime.Now;
                    while (now.AddSeconds(10) > DateTime.Now) { }
                    Invoke(reConnectCallBack);  
                }
            }
            catch
            {
                if (socket != null)
                {
                    socket.Close();
                }
                statusStripInfo.Invoke(showStatusInfoCallBack, "異步接收時發生異常,連接配接斷開!延時10秒後自動重新連接配接...");
                //延時10秒後重新連接配接
                DateTime now = DateTime.Now;
                while (now.AddSeconds(10) > DateTime.Now) { }
                Invoke(reConnectCallBack);  
            }
        }

        //異步發送
        private void AsyncSendMsg(string sendMessage)
        {
            try
            {
                Byte[] sendByte = new Byte[64];
                sendByte = Encoding.ASCII.GetBytes(sendMessage.ToCharArray());
                socket.Send(sendByte, sendByte.Length, 0);
            }
            catch
            {
                if (socket != null)
                {
                    socket.Close();
                }
                statusStripInfo.Invoke(showStatusInfoCallBack, "異步發送時異常,連接配接斷開!");
            }
        }

        //定義回調函數
        private void btnConnect_Click(object sender, EventArgs e)
        {
            
            startConnectServer();
        }

        private void startConnectServer()
        {
            Thread threadConnect = new Thread(ConnectServerThread);
            threadConnect.Start();
            btnConnect.Enabled = false;
            btnSend.Enabled = true;
            btnDisConnect.Enabled = true;
        }

        //發起連接配接請求
        private void ConnectServerThread()
        {
            statusStripInfo.Invoke(showStatusInfoCallBack, "正在連接配接……"); 
            AsyncCallback requestcallback = new AsyncCallback(RequestCallBack);
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IAsyncResult result = socket.BeginConnect(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text), requestcallback, socket);  
            while (result.IsCompleted == false)
            {
                Thread.Sleep(30);
            }
            
        }

        //回調函數,用于向服務程序發起連接配接請求
        private void RequestCallBack(IAsyncResult iar)
        {
            try
            {
                socket = (Socket)iar.AsyncState;
                socket.EndConnect(iar);
                if (socket != null)
                {
                    statusStripInfo.Invoke(showStatusInfoCallBack, "Socket連接配接成功!");
                    Thread threadReceive = new Thread(ReceiveMessage);
                    threadReceive.Start();
                }
            }
            catch
            {
                statusStripInfo.Invoke(showStatusInfoCallBack, "Socket連接配接時異常連接配接失敗!延時10秒後自動重新連接配接...");
                //延時10秒後重新連接配接
                DateTime now = DateTime.Now;
                while (now.AddSeconds(10) > DateTime.Now) { }
                Invoke(reConnectCallBack);  
            }
        }

        //接收消息
        private void ReceiveMessage()
        {
            statusStripInfo.Invoke(showStatusInfoCallBack, "資料接收中...");
            string receiveString = null;
            while (true)
            {
                try
                {
                    IAsyncResult result = receiveMsgDelegate.BeginInvoke(out receiveString, null, null);    //異步接收
                    while (result.IsCompleted == false)
                    {
                        Thread.Sleep(50);
                        if (socket.Connected == false)
                            return;
                    }
                    receiveMsgDelegate.EndInvoke(out receiveString, result);
                    if (receiveString != null)
                    {
                        receiveCount++;
                        tbxReceiveCount.Invoke(showReceiveCountCallBack, receiveCount.ToString());   //顯示接收計數
                        lstBoxMsg.Invoke(showMsgCallBack, receiveString);
                    }
                }
                catch
                {

                }
            } 
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (socket!=null && socket.Connected)
            {
                Thread threadSend = new Thread(new ParameterizedThreadStart(SendMessage));
                threadSend.Start(tbxMsg.Text);
            }
            else
                statusStripInfo.Invoke(showStatusInfoCallBack, "socket沒有連接配接!");
        }

        //發送消息
        private void SendMessage(object state)
        {
            statusStripInfo.Invoke(showStatusInfoCallBack, "正在發送...");
            try
            {
                IAsyncResult result = sendMsgDelegate.BeginInvoke(state.ToString(), null, null);    //異步發送
                while (result.IsCompleted == false)
                {
                    Thread.Sleep(30);
                }
                sendMsgDelegate.EndInvoke(result);
                statusStripInfo.Invoke(showStatusInfoCallBack, "發送完畢!");
                sendCount++;
                tbxSendCount.Invoke(showSendCountCallBack, sendCount.ToString());      //顯示發送計數
            }
            catch
            {
                statusStripInfo.Invoke(showStatusInfoCallBack, "資料發送時異常,發送失敗!");
            }  
        }

        private void btnDisConnect_Click(object sender, EventArgs e)
        {
            if (socket != null)
            {
                socket.Close();
            }
            toolStripStatusInfo.Text = "連接配接斷開!";
            btnConnect.Enabled = true;
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            lstBoxMsg.Items.Clear();
            sendCount = 0;
            receiveCount = 0;
            tbxSendCount.Text = sendCount.ToString();
            tbxReceiveCount.Text = receiveCount.ToString();
        }

    }
           

繼續閱讀