경험을 통해서

[C#] TCP 통신 뜯어보기 1탄 본문

Coding Diary/C,C++,C#

[C#] TCP 통신 뜯어보기 1탄

할일이 많다 2025. 1. 19. 20:50

다들 많이 찾아볼 거다 IoT 관련 업종이나 FA(공장자동화) 쪽에서는

통신이 무척이나 중요하기 때문이다.

 

이번 시간에는 순수하게 C#에서 제공하는 라이브러리만 사용해서 만들어보자

 

확인해볼 사항

1.  재 연결 interval을 얼마로 둘것인가?

2.  끊어진지 어떻게 확인할 것인가?

3. 마냥 기다릴 수 만은 없기 때문에 몇 초 정도 후 데이터 미 송신시 재 연결을 진행할 것인가?

4. 메모리 누수가 안 생기면서 서버에 들어오는 모든 요청을 답할 수 있을 것인가?

5. Ack 값이 한번에 전부 수신이 안될경우 몇 초정도 딜레이를 두고 대기할 것인가.?

등등...

 

정말 완벽한 메모리의 누수가 없는 통신이 가능하면서 데이터를 송수신 할 떄

다 처리할 수 있을 것인가?

 

프로그램을 항상 개발할 때 드는 생각이다...

 

서론이 너무 길었고 어쨌든 서론의 포인트는

 

 

완벽한 통신은 고민과 경험에서 나온다.

 

 

 

 

이제 코딩을 해보자

 

최근에 깨닫게 된 걸 먼저 상기하고 만들려고 한다.

이 글을 보기 전에 2가지만 확인하자!

1. 코드의 재사용성

2. 무조건 비동기가 좋은건 아니기에 구분해서 사용하자

 

 1. enum을 사용해서 클래스의 인스턴에 구분을 두자

    public enum FuctionTCP
    {
        [Description("SERVER CREATE")]
        SERVER = 0,
        [Description("CLIENT CREATE")]
        CLIENT = 1
    }

 

 

위와 같이 구분을 둘 경우에는 열거형 자료를 사용해서 구분하는게 좋다(내 기준... )

 

그래서 클래스 생성자에서 구분해서 받도록 구성해보자

      public tcpHelper(FuctionTCP brDistinguish)
      {
         switch (brDistinguish)
          {
              case FuctionTCP.SERVER:
                  _servers = new List<tcpClients>();
                  _listener = new TcpListener(System.Net.IPAddress.Any, 5000);
                  _listener.Start();
                  //프로그램 종료 시에 같이 종료하기 위한 값
                  _programRunning = true;                  
                  break;
              case FuctionTCP.CLIENT:     
              _clients = new TcpClient();
              _clients.connect();
              initConnect(_clients);                  
                  break;
              default:
                  break;
          }         
      }
      
      public async void initConnect(TcpClient tempCli)
      {      	
      	Netstream tempNS = tempCli.GetStream();
        //여기선 값을 수신만 한다.
        //...
        //Netstream 관련 부분을 공부하면 관련 함수를 사용해서
        //더 코드를 가용성있게 사용할 수 있다.
      }

 

 

 

이렇게 되면 해당 클래스를 선언만 해도 별도의 구문 없이 자동으로 연결 시도와 서버가 열려진다.

물론 재 연결 파트를 위해서 connect 함수를 별도로 빼놓은 거다

 

Timer _timer;

public void connectTry()
{
//C#에서 제공하는 connected는 
//해당 소켓이 연결된 적이 있으면 연결되어 있지 않아도 true를 반환한다.
//그래서 별도의 구분 값이 필요하다.
	if(!isConnect)
    {
        try
        {
        //비동기를 사용하지 않은 이유는
        //타이머 자체가 스레드임
            _clients.connect();
            isConnect = true;
        }
        catch()
        {
            isConnect =false;
            //연결을 실패할 경우 실행할 로직 추가
            //...
        }
    }
}

 

( 변수의 대소문자 구분이 안되는 경우는 양해 .... 부탁)....

 

물론 코드 자체가 원래 창작성이 있어서 다 같을 수는 없어서

환경에 따라서 자기가 알아서 쓰면 됨 ㅎㅎ

 

 

마지막으로 적어놓을 말은

개인적으로 제일 생각없이 짠 코드는 응답값 확인도
없이 임의로 끊는 코드인거 같다.(딜레이는 좀 길게 주자.... 재송신 코드도 필요)