본문으로 바로가기
homeimage
  1. Home
  2. 컴퓨터/프로그래밍
  3. TCP/IP 연결 끊김 해결 방법

TCP/IP 연결 끊김 해결 방법

· 댓글개 · 바다야크

TCP/IP 연결 지향 프로토콜

TCP/IP를 연결 지향 프로토콜이라고 합니다. 처음 TCP/IP 소켓 프로그래밍을 학습할 때 "연결 지향 프로토콜"이라는 말이 생소해서 뭔 뜻인가 했습니다. 연결 지향? 통신이라면 당연히 연결되어야 하는 것 아닌가? TCP/IP로 통신한다고 라인을 깔아서 직접 연결한다는 것은 아닐 텐데.

연결 지향 프로토콜이란

그렇습니다. 당연히 연결 지향 프로토콜이라고 물리적으로 선을 깔아서 직접 연결하는 것은 아니고요, TCP 프로토콜이 소프트웨어적으로 상대 시스템과 통신이 끝날 때까지 연결을 유지시켜 줍니다.

UDP/IP 프로토콜과 비교하면 이해하기 쉽습니다. UDP/IP는 좀 전에 A 컴퓨터에 데이터를 전송했음에도 이번에도 다음에도 A 컴퓨터로 데이터를 보내려면 매번 A 컴퓨터의 IP를 넣어서 전송해야 합니다. 온종일 A 컴퓨터하고만 통신한다고 해도 A 컴퓨터의 IP를 지정해 주어야 합니다.

그러나 TCP/IP는 데이터를 주고받기 전에 접속부터 시도하고 상대방이 수락해서 연결이 되어야 통신이 가능하며, 이후에는 데이터만 주고받습니다. 즉, UDP/IP처럼 데이터를 전송할 때마다 타깃 IP를 지정할 필요가 없습니다. 이렇게 TCP/IP 프로토콜은 상대방과 연결 고리를 만들어 놓고 통신합니다. 그러므로 데이터를 전송할 때 이미 타깃이 결정된 상태이며 어느 한쪽이 연결을 끊을 때까지 TCP/IP가 연결을 유지시켜 줍니다.

매번 타깃을 지정하는 UDP/IP 와는 달리 가상의 통로를 만들어서 데이터를 주고받는 TCP/IP를 연결 지향 프로토콜이라고 합니다.

TCP/IP 알 수 없는 연결 끊김

TCP/IP는 매우 편리한 프로토콜이지만, 몇 가지 단점이 많은 프로그래머의 속을 썩입니다. 그중에 하나가 알 수 없는 연결 끊김입니다. TCP/IP는 연결 지향 프로토콜이라서 TCP 프로토콜에 의해 연결이 계속 유지되어야만 통신이 가능한데, 양쪽 시스템이 전혀 의도하지 않았음에도 연결이 끊어질 때가 있습니다.

  • TCP/IP 프로토콜은 상대에게 접속을 요청하고
  • 접속 수락에 따라 연결이 됩니다.
  • 연결 후에는 데이터를 전송하고,
  • 작업이 완료되면 연결을 끊습니다.

내가 연결을 끊든, 상대방이 끊든, 아니면 동시에 끊던지 간에 연결이 없어지면 더 이상 데이터를 보내거나 기다려서는 안 되겠습니다. 당연하죠? 그런데 나도, 상대방도 연결을 끊지 않았음에도 TCP/IP는 의도치 않게 끊김이 발생합니다.

물리적으로는 랜 케이블이 빠질 수 있고요, 허브가 이상해지거나 통신사 시스템의 전원이 끊길 수도 있습니다. 아니면 주변 노이즈가 매우 심각해서 TCP/IP 프로토콜이 제 기능을 제대로 못할 수도 있습니다.

그렇다면 환경이 좋으면 안 끊길까요? 끊깁니다. 같은 허브에 물린 두 대의 컴퓨터로 통신하는데도 TCP/IP 연결이 끊어집니다. 허브와 컴퓨터의 전원에 아무런 문제가 없고 주변에 통신을 방해하는 노이즈가 없는데도 무슨 이유인지 연결이 끊어집니다.

연결이 끊기면 다시 접속하면 되겠지만, 답답한 것은 연결이 끊어졌다는 것을 알 수 없는 경우가 있다는 것입니다. 더욱 큰 문제는 이런 경우 데이터 전송을 위해 write() 함수를 호출하면 에러라도 나면 다행인데, 아무런 일 없다는 듯 성공을 반환합니다. 그래서 계속 정상적으로 통신하고 있는 줄로 착각한다는 것이죠.

교과서적인 내용에 따르면 TC/IP 프로토콜은 연결 끊김을 알 수 있습니다. 그러나 항상 이상적이지 않다는 것이 문제입니다. 통신이 잘 되다가도 갑자기 어느 순간부터 통신이 안 됩니다. 데이터를 보내고 있는데도 상대방은 전혀 수신하지 못합니다. 양쪽 시스템이 연결 끊김을 인식하지 못해서 평소처럼 데이터를 전송하고 다른 한쪽은 수신을 위해 대기하지만, 실제로는 연결이 끊긴 것이죠.

TCP/IP 알 수 없는 연결 끊김 해결 방법

TCP/IP 프로토콜이 연결 지향 프로토콜임에도 의도치 않은 끊김이 발생합니다. 연결이 끊겼다는 것일 인지할 수 있다면 유별난 일이 아닙니다. 다시 접속해서 통신하면 되니까요.

문제는 프로그램에서 연결 끊김을 인지하지 못할 뿐만 아니라 전달할 수 없는 상태인데도 전송 함수에서 아무런 에러가 발생하지 않는 경우입니다. write() 함수에 걸어 놓은 예외 상황 처리 루틴이 무용지물이 되는 상황이라 프로그램은 돌고 있어도 통신은 끊긴 것입니다. TCP/IP 프로토콜의 이런 특성을 모르고 대처하는 코드를 넣지 않는다면 난처한 일이 발생합니다.

현장에 납품할 때는 잘 돌던 장비가 며칠 안 돼 작동 안 한다는 연락을 받게 됩니다. 현장에 가서 껐다 켜면 작동이 되는데 아무리 봐도 이상한 점이 안 보입니다. 일단 통신이 되니까 돌아왔는데 또 멈추었다는 연락이 반복됩니다.

그렇다면 TCP/IP 프로토콜의 인지하지 못하는 끊김 문제를 어떻게 해결할 수 있을까요?

전송이 필요할 때만 TCP/IP 연결

서버에 전송할 데이터가 있을 때만 접속해서 데이터를 전송하고 연결을 끊습니다. 원샷원킬하듯이 접속 요청하고 전송 후에는 연결을 끊는 것이죠. 매번 접속해야 해서 번거롭지만, 계속 연결된 상태로 통신하는 것보다는 안전합니다. 그러나 전송할 데이터가 많고  전송 주기가 짧은 시스템에서는 무리가 있습니다. 또한, 접속되었다고 반드시 전송에 성공하리라는 보장도 없습니다.

서버가 항상 응답

가장 확실한 방법은 데이터를 보낼 때마다 잘 받았다는 응답을 확인하는 것입니다. TCP/IP 프로토콜에서 전송했는데 응답이 없다면 서버가 너무 바쁘거나 연결 끊김일 수 있습니다. 그러므로 다시 접속하고 전송합니다.

단점이라면 데이터가 많을 경우 시간을 많이 소모한다는 것입니다. 100개의 데이터를 보내려면 100번의 응답을 기다려야 하니까요. TCP/IP와 UDP/IP는 시리얼 통신과 달리 데이터 손상이 없습니다. TCP와 UDP가 데이터의 안정성을 지켜 줍니다. 그래서 두 프로토콜 모두 데이터 깨짐을 확인하기 위해 CRC를 넣어서 보낼 필요가 없습니다. 프로그래머 대신에 TCP와 UDP가 수고해 줍니다. 이럼에도 매번 서버로부터 잘 받았다는 응답을 받는 것은 비효율적일 수 있습니다.

그러나 통신량이 부담되지 않을 정도라면 서버로부터 항상 응답을 받는 것이 안전하고 마음이 편합니다. 응답을 받았다면 확실히 전송된 것이니까요. 잘못된 생각도 아닙니다. 원래 서버와 클라이언트는 질의와 응답하는 관계이니까요. 그래도 시간이 너무 걸린다면 100개의 데이터를 보내고 마지막 한 번의 응답으로 확인할 수 있고요.

결론은 TCP/IP 프로토콜에서는 어느 한쪽에서만 데이터를 전송해서는 안 된다는 것입니다. 전송하기만 하면 상대방이 정말 수신하고 있는지, 아니면 연결 끊김으로 허무한 작업을 하고 있는지 알 수 없습니다.

연결 확인 응답

송신 데이터에 응답을 기다리는 대신에 별도로 연결을 확인하는 패킷을 주고받는 방법이 있습니다. 데이터를 보낼 때는 응답을 받지 않지만, 주기적으로 연결 확인을 위한 별도의 패킷을 전송하고 이때는 응답을 받습니다. 만일 응답이 없다면 연결이 끊겼다고 판단해서 다시 접속을 시도합니다. 주고받는 데이터가 없더라도 연결 확인 코드를 주기적으로 주고받는다면 모니터링 화면에 연결 상태를 표시하는 데 사용할 수 있습니다.

생각의 오류

연결 확인 응답을 별도의 프로그램으로 작성?

데이터를 전송하기만 하되 간간이 주기적으로 연결을 확인하기로 했습니다. 그러나 데이터를 보내는 루틴에 연결 확인 응답을 끼워 넣는 것이 불편해서 따로 프로그램을 짜서 실행하면 어떨까요? 예를 들어서 서버로 데이터를 전송하는 A 프로그램과 서버의 응답을 주기적으로 확인하는 B 프로그램을 동시에 실행하는 것이죠.

결론부터 말씀드리면 완전한 방법이 못 됩니다. 물리적인 오류는 알 수 있을 것입니다. 서버가 죽거나, LAN 케이블이 빠지는 등 통신 불가 상태를 알 수는 있습니다. 그러나 인지하지 못하는 연결 끊김을 확인할 수 없습니다. A 프로그램은 연결 끊김으로 데이터 전송이 안 되는데, B 프로그램은 서버로부터 응답을 받을 수 있기 때문입니다. 즉, 두 프로그램이 똑같은 서버와 접속했다고 해서 둘 다 연결이 끊기지 않을 수 있다는 것입니다.

같은 프로그램에 A, B 루틴으로 나누어 넣어도 마찬가지입니다. A 루틴이 서버와 연결한 그 소켓을 B 루틴도 사용해야 연결 끊김을 알 수 있습니다. A 루틴 따로 B 루틴 따로 서버에 접속한다면 연결된 소켓이 다르므로 B 루틴의 연결로는 A 루틴의 연결 상태를 정확히 확인할 수 없습니다.

몇 시간마다 재접속?

몇 시간마다 일부러 끊었다가 다시 접속하는 것은 어떨까요? 물론, 한 번 접속으로 계속 통신하는 것보다는 낫겠습니다만, 그렇다면 과연 몇 시간마다 재접속하면 안전할까요? 두 시간? 한 시간? 30분마다?

코딩 방법이 간단해지는 장점이 있을 수 있지만, 장담하기 어렵다는 것이 문제입니다. 사무실에서는 두 시간마다 재접속해도 아무런 문제가 없는데 현장에서는 5분간으로 줄여도 1분간 통신되다가도 4분간 먹통이 될 수 있습니다. 내 자리에서는 잘 도는데 밖에만 나가면 이상해 지는 시스템이라면 여럿 고생하게 합니다.

이렇게 저렇게 하면 될 것 같은데 실제로 해 보면 잘 안 되는 것이 통신 프로그램입니다. 교과서 내용에 따라 충실히 작성해도 현장에서는 생각하지 못하는 문제를 경험하게 됩니다. 그래서 통신 프로그램은 참 어렵습니다. 제 경험에 따라서 글을 썼습니다만, 더 좋은 방법이 있다면 댓글로 부탁을 드립니다. 본문에 추가해서 많은 분과 지식을 나누었으면 좋겠습니다.

SNS 공유하기
💬 댓글 개
최근글
이모티콘창 닫기
울음
안녕
감사해요
당황
피폐

이모티콘을 클릭하면 댓글창에 입력됩니다.