C#

C# 소켓통신 TcpClient (비동기, 재접속, TcpServer 예제포함)

sheepone 2021. 6. 18. 15:35
반응형

비동기 재접속이 가능한 TCPCLIENT

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;

namespace TCPClient01
{
    public partial class Form1 : Form
    {
        TcpClient mTcpClient;
        byte[] mRx;

        //서버에 연결되어 있는지 확인
        bool bConnected = false;
        private bool Connected { get => mTcpClient == null ? false : mTcpClient.Connected && bConnected; }

        //접속시 사용한 IP PORT
        int iPort;
        IPAddress iPAddress;

        //재접속 타이머
        System.Timers.Timer timer1 = new System.Timers.Timer();

        public Form1()
        {
            InitializeComponent();

            timer1.Interval = 1000;
            timer1.Elapsed += new System.Timers.ElapsedEventHandler(timer1_Elasped);
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (mTcpClient != null && Connected /*mTcpClient.Connected*/) return ; //연결이 되어 있는데 또 연결 방지용, 서버쪽에 연결된 노드가 늘어남

            IPAddress ipa;
            int nPort;

            try
            {
                if (string.IsNullOrEmpty(tbServerIP.Text) || string.IsNullOrEmpty(tbServerPort.Text))
                    return;

                if (!IPAddress.TryParse(tbServerIP.Text, out ipa))
                {
                    MessageBox.Show("Please supply an IP Address.");
                    return;
                }

                if (!int.TryParse(tbServerPort.Text, out nPort))
                {
                    nPort = 23000;
                }

                mTcpClient = new TcpClient();
                mTcpClient.BeginConnect(ipa, nPort, onCompleteConnect, mTcpClient);

                iPAddress   = ipa  ;
                iPort       = nPort;
                bConnecting = true ;
                timer1.Start();


            }
            catch (Exception exc)
            {
                bConnected = false;
                MessageBox.Show(exc.Message);
            }
        }

        bool bFirstConnect = false;
        bool bConnecting = false ;
        void onCompleteConnect(IAsyncResult iar)
        {
            TcpClient tcpc;

            try
            {
                //iar.AsyncWaitHandle.WaitOne(1000, false);

                tcpc = (TcpClient)iar.AsyncState;
                tcpc.EndConnect(iar);
                mRx = new byte[512];
                tcpc.GetStream().BeginRead(mRx, 0, mRx.Length, onCompleteReadFromServerStream, tcpc);
                bConnected = true; //연결 성공

            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message);
                bConnected = false; //연결 실패

            }
            bConnecting = false;
        }

        void onCompleteReadFromServerStream(IAsyncResult iar)
        {
            TcpClient tcpc;
            int nCountBytesReceivedFromServer;
            string strReceived;
            
            try
            {
                tcpc = (TcpClient)iar.AsyncState;
                nCountBytesReceivedFromServer = tcpc.GetStream().EndRead(iar);

                if (nCountBytesReceivedFromServer == 0)
                {
                    MessageBox.Show("Connection broken.");
                    return;
                }
                strReceived = Encoding.ASCII.GetString(mRx, 0, nCountBytesReceivedFromServer);
                string s1 = Encoding.ASCII.GetString(mRx, 0, nCountBytesReceivedFromServer-1);
                if(mRx[nCountBytesReceivedFromServer-1] != '\n') return;
                printLine(strReceived);

                mRx = new byte[512];
                tcpc.GetStream().BeginRead(mRx, 0, mRx.Length, onCompleteReadFromServerStream, tcpc);

                bConnected = true; //연결 성공

            }
            catch (Exception exc)
            {

                bConnected = false; //연결 실패
                MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public void printLine(string _strPrint)
        {
            tbConsole.Invoke(new Action<string>(doInvoke), _strPrint);
        }

        public void doInvoke(string _strPrint)
        {
            tbConsole.Text = _strPrint + Environment.NewLine + tbConsole.Text;
        }

        byte[] tx;
        private void tbSend_Click(object sender, EventArgs e)
        {
            //byte[] tx;
            
            if (string.IsNullOrEmpty(tbPayload.Text)) return;

            try
            {
                if (!Connected) return;

                tx = Encoding.ASCII.GetBytes(tbPayload.Text + "\r\n");

                if (mTcpClient != null)
                {
                    if (mTcpClient.Client.Connected)
                    {
                        mTcpClient.GetStream().BeginWrite(tx, 0, tx.Length, onCompleteWriteToServer, mTcpClient);
                    }
                }
            }
            catch (Exception exc)
            {
                bConnected = false;
                MessageBox.Show(exc.Message);
            }
        }
        void onCompleteWriteToServer(IAsyncResult iar)
        {
            TcpClient tcpc;

            try
            {
                tcpc = (TcpClient)iar.AsyncState;
                tcpc.GetStream().EndWrite(iar);
                //bCompleted = true;
            }
            catch (Exception exc)
            {
                //bCompleted = false;
                MessageBox.Show(exc.Message);
            }
        }

        private void timer1_Elasped(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            bConnected = mTcpClient.Connected;
            if (!mTcpClient.Connected && !bConnecting)
            {
                bConnecting = true;
                mTcpClient.Close();
                mTcpClient = new TcpClient();
                mTcpClient.BeginConnect(iPAddress, iPort, onCompleteConnect, mTcpClient);
            }
            timer1.Enabled = true;
        }


    }
}

 

테스트 예제

연결

서버 실행후에 Start Listening 클릭

클라이언트 실행후에 Connect 클릭

Write & Read

클라이언트측 Send 클릭 - 서버측 확인후 현재시간 전송

서버측 Clients에서 연결된 클라이언트 선택후 Send 클릭 - 클라이언트측 받은 메시지 표기

 

재접속하려면 한번 Send 필요.

 

관련 소스 첨부

TCPServer01 (1).zip
0.22MB
TCPClient01.zip
0.05MB

반응형