본문 바로가기

Coding Diary/C,C++,C#

TCP 통신의 패킷 처리하기(클라이언트 편)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace TCP_model
{
    public partial class Form1 : Form
    {
        Socket fSocket;
        Thread fRec_thread;
        Thread fReconnection;
        IPAddress fiA;
        IPEndPoint fEP;
        private bool fconnection;
        private int fCon_Err = 0; //연결이 물리적으로 끊겼을 경우 Receive 함수의 반환 값이 0이 되는 것을 확인하여 2번이상 0이 반환되면 일방적으로 끊는다
        private string fmsg="";
        private int [] fCnt = new int[3];
        Form2 fFormshow;
        TCP_Class clTCP;
        /// <summary>       
        /// g가 붙은 변수는 외부 전역 변수
        /// f가 붙은 변수는 내부 전역 변수
        /// s가 붙은 변수는 지역 변수
        /// c는 조건 반복등에서만 쓰이는 변수 - foreach 문 안에 주로 쓰임
        /// ps 반환 값이 없는 외부 함수
        /// pf 반환 값이 있는 내부 함수
        /// gs 반환 값이 없는 외부 함수
        /// gf 반환 값이 있는 내부 함수
        /// cl은 사용자 클래스 인스턴스
        /// 
        /// </summary>

        public Form1()
        {
            InitializeComponent();
            fFormshow = new Form2();
            clTCP = new TCP_Class();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (!fconnection)
            {
                fRec_thread = null;
                fconnection = true;
                fRec_thread = new Thread(new ThreadStart(psReceive));
                fRec_thread.IsBackground = true;
                fRec_thread.Start();
            }
        }

        private void btn_close_Click(object sender, EventArgs e)
        {
            
             fSocket.Close();
            fconnection = false;
            
        }

        private void Form1_Load(object sender, EventArgs e)
        {            
            //===============기존의 TCP의 값들을 설정하여 둔다============//
            fiA = IPAddress.Parse("127.0.0.1");
            fEP = new IPEndPoint(fiA, 101);
            //===============기존의 TCP의 값들을 설정하여 둔다============//
            fReconnection = new Thread(new ThreadStart(psReconnection));
            fReconnection.IsBackground = true;
            fReconnection.Start();   
        }

        private void psReconnection()
        {
            while (true)
            {
                if (!fconnection)
                {
                    fCnt[1]++;
                    try
                    {
                        fSocket = null;
                        fSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        fSocket.Connect(fEP);
                        fconnection = true;
                    }
                    catch (Exception)
                    {
                        fSocket = null;                        
                    }


                    if (fconnection)
                    {
                        fRec_thread = null;

                        fRec_thread = new Thread(new ThreadStart(psReceive));

                        fRec_thread.IsBackground = true;

                        fRec_thread.Start();
                    }
                    

                }

                Thread.Sleep(1000);
                
            }
        }

        private void psReceive()
        {
            while (fconnection)
            {                
                byte[] receiveBuffer = new byte[512];
                int length = 0;
                try
                {
                    length = fSocket.Receive(receiveBuffer, receiveBuffer.Length, SocketFlags.None);
                }
                catch (Exception)
                {

                    fconnection = false;
                }
                
                if (length != 0) // 반환 되는 값이 0일 경우는 경험 상 물리적인 이더넷 통신이 끊겼을 경우 
                {
                    fCon_Err = 0;
                    fmsg =fmsg + Encoding.UTF8.GetString(receiveBuffer, 0,
                    length);
                 
                    char sSTX_ASCII = Convert.ToChar(0x02);

                    string[] sPacket = fmsg.Split(sSTX_ASCII);
                    fmsg = "";
                    foreach (string cPkt in sPacket)
                    {
                        switch (clTCP.gfConfirm_packet(cPkt, 0x03))
                        {
                            case 0:
                                //크로스 스레드 오류로 대리자 함수로 listbox와 richText에 각각 즉각 추가 함수//
                                listBox1.Invoke(new MethodInvoker(delegate
                                {
                                    listBox1.Items.Add(string.Format("({0}) : Message : {1}", DateTime.Now.ToString(), cPkt));
                                }));
                                fmsg += cPkt;
                                break;                                                                                                              

                            default:
                                
                                richTextBox1.Invoke(new MethodInvoker(delegate
                                {
                                    richTextBox1.AppendText(string.Format("({0}) : Message : {1}\n", DateTime.Now.ToString(), cPkt));
                                }));                                
                                break;
                        }
                    }                

                }
                else
                {
                    fCon_Err++;
                    fconnection = fCon_Err % 2 == 0 ? false : true;
                }
                Thread.Sleep(10);
            }            
            fSocket.Close();
            // 재연결된 값을 표현하기 위해 배열로 선언하여 연결 해제 시 카운트가 올라간다
            fCnt[0]++;
            fconnection = false;
        }





        private void btn_confirm_Click(object sender, EventArgs e)
        {
            if (fiA != null)  pan_fIA.BackColor = Color.Green;
            else pan_fIA.BackColor = Color.Red;

            if (fEP != null) pan_fIE.BackColor = Color.Green;
            else pan_fIE.BackColor = Color.Red;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            label1.Text = fCnt[0].ToString();//psReceive thread
            label2.Text = fCnt[1].ToString();//psReconnection thread 
            if (fmsg != "") 
            {
                listBox1.Items.Add(string.Format("({0}) : Message : {1}", DateTime.Now.ToString(), fmsg));
                fmsg = "";
            }
        }

        private void pan_fIE_Paint(object sender, PaintEventArgs e)
        {

        }

        private void pan_fIE_Click(object sender, EventArgs e)
        {
            if (!fFormshow.Visible)
            {
                fFormshow.Show();
            }
            
        }
    }
}

확실히 미완성 패킷 처리 부가 힘들고 끊겼을 경우 그 순간을 잡기가 힘들다......

 

코드 설명은 다음 기회에...