ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Linux] socat 사용하기
    IT Study/OS 2026. 6. 20. 14:30

     

    교수님께로부터 과제를 받았다. 

    RS-232통신을 서로 다른 기종의 서버 간에서 SW적으로 구현해보아라 ! 

     

    두뇌 풀가동

     

    RS-232 Serial port를 직접 서버 2대에 연결을 해보았으나, 하드웨어를 다루기 위해서는 Linux /dev폴더에서 작업을 진행해야한다. 이 dev파일은 일반 사용자에게 권한이 없다. 그러나 이제서야 석사과정 1년차인 인 나에게 당연히 sudo권한이 없기 때문에 socat을 사용하여 SW적으로 RS-232를 구현해야했다. 

     

     

    RS-232를 SW적으로 구현하기 위해 두 서버간의 연결이 필요하다. Linux에서 가상 포트를 만들어주는 것이 바로 socat 라이브러리, 그리고 socat명령어를 통해 socket을 사용한다. 그리고 이 socket을 사용하기 위해서 socat라이브러리를 설치해야한다. (이는 관리자 권한을 가진 교수님께 부탁드렸다.)

     

    sudo dnf install socat -y

     

     

     

    그래서 지금부터 다룰 내용은 '물리적인 Serial Port가 없고 루트 권한이 제한된 일반 사용자 환경에서 리눅스 네트워크 소켓 가상화 도구인 socat과 ssh터널링을 이용해서 서로 다른 기종 서버 간 가상 RS-232파이프라인을 구축하는 방법'이다. 

     

    가장 먼저 다루어볼 개념은 RS-232는 저번에 포스팅해보았고, 이번엔 Linux socat ! 


    Socket 이 뭔데? 

    원래 영어 단어 Socket의 뜻은 벽에 붙어있는 전기 콘센트 구멍이나 전구를 돌려 끼우는 소켓이나, 어떤 대상에 다른 부품이나 장치를 끼워 연결하기 위한 접속구이자 통로를 의미한다. 

    읭 ??

     

    소켓에 플러그를 꽂아야 전기가 흐르는 것처럼 네트워크에서도 똑같은 개념이 필요해서 동일한 단어를 가지고 왔다. 컴퓨터 공학에서 소켓은 네트워크선 양 끝에 소프트웨어적으로 붙이는 데이터 플러그(접속 창구)를 의미한다. 

     

    더보기

    IP 주소 - 포트 번호 - 소켓 

     

    컴퓨터가 다른 컴퓨터와 통신하기 위해서는 랜선에 무작정 데이터를 던질 수 없다. 정확한 위치에 딱 갖다 꽂아야하는데, 이를 위해 IP, port는 익히 들었을 것이다. 

     

    • IP 주소: 데이터가 찾아갈 아파트 단지(건물 주소) - 192.168.0.1
    • 포트(Port) 번호: 그 아파트의 동/호수 - 4001 
    • 소켓(Socket): 그 동/호수 문 앞에 달아놓은 우편함 구멍 

    음, 그런데 내가 처음에 한 고민이 있다. 

    보통 IP/Port번호를 통해 파일이나 데이터를 보내면 갔는데 .. 예를 들어 ssh나 scp같은 명령어를 통해서 말이다. 그리고 심지어 내가 통신을 하려고 하는 두 서버 간에는 이미 ssh로 연결이 되어있다. 그럼 그냥 데이터를 보내면 안될까? 

     

    NO!!! 

     

    지금 내가 하려는 것은 송신측 matlab상에서 데이터를 읽고 수신측 matlab에 데이터를 전송하는 것이다. 프로그램 간의 언어 장벽이 있기에 이것을 극뽁해야만한다. 

     

    그동안 하던 통신은: 내 터미널 창 → ssh → LAN → 상대 터미널 창(텍스트 전달)

    지금 해야하는 통신은: 내 매트랩 → ssh → LAN → 상대 매트랩 

     

    매트랩은 아무래도 리눅스 전용 원격 프로그램이 아니기 때문에 .. 내 매트랩에서 보낸 데이터를 상대 매트랩에서 받아야하는데, 둘 사이에 데이터가 오갈 수 있는 전용 우편함이 양쪽 서버에 없다 !! 그래서 중간에 socat을 이용하여 매트랩 전용 특수 통로를 수동으로 개통해준 것이다. 

     

     

    그럼 socat은 뭔데 ? 

    socat = SOcket CAT, socket은 앞서 말한 소켓, cat은 리눅스에서 텍스트 파일을 읽고 쓰는 cat명령어를 의미한다. cat명령어는 파일의 내용을 화면의 뿌려주는 명령어이다.

     

    내가 느끼기에 socat은 연결의 의미가 강한데, cat으로 표현하는게 약간 이해가 안간다. (아직 지식이 부족해서 그런가보다.) 어쨋든 그냥 이런 약어구나 ~ 하고 다른 중요한 개념부터 살펴보자 

     

     이 socat은 두 개의 서로 다른 데이터 흐름(Stream)을 상호 연결해주는 중계기 역할을 한다. 연결할 수 있는 것들은 다음과 같다. 

    • 네트워크 소켓(TCP, UDP, SSL)
    • 로컬 파일 시스템 및 디렉터리 
    • 시스템 표준 입출력(STDIO)
    • 가상 시리얼 포트(PTY, Pesudo Terminal) 

    쉽게 표현하자면, socat을 양손에 파이프 어댑터를 가지고 있는 배관공이다. 한 예시로, Serial Port파이프와 TCP/IP 네트워크 파이프를 연결하여 이 둘을 맞물려주는 역할을 한다. 그럼 이 파이프를 통해 Serial Port로 들어간 데이터가 네트워크 랜선을 타고 반대편으로 흘러가는 것이다. 

     


    socat 명령어의 기본 문법 규칙 

     

    socat은 항상 두 개의 주소(Address)를 인자로 받는다. 

     

    socat [옵션] <첫 번째 주소> <두 번째 주소>

     

    첫 번째 주소에서 들어오는 데이터를 두 번째 주소로 보내도, 동시에 두 번째 주소에서 들어오는 데이터를 첫 번째 주소로 전달한다. (기본적으로 양방향 통신 가능) 

     

     


    직접 socat 사용해보기 

     

    ① 터미널 입력을 TCP서버로 전달하기 

     

    내가 터미널에 치는 글자(STDIO)를 네트워크 포트(TCP)로 내보내는 간단한 소켓 서버를 만들 수 있다. 

     

     

    1단계 (서버 켜기): 7777번 포트를 열고 대기하면서 들어오는 데이터를 화면(STDIO)에 보여준다. 

    socat TCP-LISTEN:7777 STDIO

     

    2단계(클라이언트 접속): 다른 터미널 창을 열고 접속한다. 

    socat STDIO TCP:127.0.0.1:7777

     

     

     

    2번 터미널에 글자를 치고 엔터를 누르면 실시간으로 1번 터미널에 글자가 나타난다 ! 

     

     

     

     

     

     

    ② 동일한 서버 내에서 RS-232통신 시뮬레이션 

    동일한 리눅스 서버끼리 RS-232통신을 하는 시뮬레이션을 실행한다. 명령어를 하나하나 뜯어보자 

    socat -d -d PTY,link=/tmp/vtty0,raw,echo=0 PTY,link=/tmp/vtty1,raw,echo=0

     

    • -d -d(Debug/Discovery): 상세 로그(Log) 출력 옵션으로 가상 포트가 성공적으로 만들어졌는지, 현재 데이터가 오고 가고 있는지를 터미널 창에 디버깅 메시지를 보여준다. 
    • PTY는 앞서 말했듯, 가상 Serial Port를 의미한다. 실제 하드웨어가 아닌 가짜 의사 터미널/Serial 장치를 만드는 타입 지정 옵션이다. 
    • link=/tmp/vtty0: 가상 포트 파일이 생성될 위치와 이름이다. 
    • raw: 데이터에 어떠한 변형이나 가공 없이 보낸다(0,1 비트 스트림)
    • echo=0 : 내가 보낸 데이터를 확인하는 기능인(echo)를 끈다. 

    이 명령어를 통해 동일한 서버 내에서 /tmp/vtty0, /tmp/vtty1이라는 가상의 포트가 생겼다 ! 이를 매트랩에서 활용하는 방법에 대해서는 다음 포스팅에 작성할 예정이다. 

     

     


     

    ③ ssh명령어와 소켓을 통해 네트워크를 결합하는 방법 

     

    현재 RS-232 구현을 위해 연구실의 서버를 연결하는 방식이다.

     

    동일한 기종에 대해서는 쉽게 연결이 되었지만, 이기종간 연결을 처음에 어떻게 해야하나.. 고민을 많이 했다.

     

    당시 내가 가진 단서는 

    1. Bastion Host 아키텍처 사용(gateway서버와 내부 서버로 동일한 LAN상에 있음) 

    2. socat으로 가상 포트를 만들 수 있음 

     

    → 그럼, 호스트 서버와 내부 서버가 TCP/IP, ssh로 연결되어 있으니, 이 연결을 빌려서 가상 포트를 만들 수 있지 않을까 ? 

    이 고민이 정답이었고, 실제 데이터는 TCP/IP로 전송을 하고, 보내는 송신부와 수신부에서 socat을 통해서 던지는 역할을 했다. 

     

    조금 더 쉽게 말하자면, 물리적/네트워크 기저에는 TCP/IP가 깔려있고, 그 위에서 보안(ssh)와 현재 구현하고자 하는 하드웨어 가상화(socat) 프로토콜이 돌아가는 구조이다 !!! 

     

    음 진짜 조금 더 쉽게 말하자면, 데이터를 실어 나르는 주체는 TCP/IP이고, 서버 끝단에서 매트랩과 소켓을 이어주는 포멧은 socat이 변환을 해주는 개념이다. 그리고 이 모든 데이터가 전송되는 과정에서 데이터 암/복호화는 ssh이 전담한다. 

     

    더보기

     * P는 gateway, 즉 Bastion host 서버이고, K는 내부 서버 

     

    [송신단: 서버 P (Pascal)]

    ① 응용 레이어 (MATLAB): 가상 RS-232 프레임 데이터 생성 (Byte Stream)

    ↓ (로컬 파일 시스템 인터페이스: /tmp/vtty0 장치 파일에 쓰기)

    ② 직렬화/중계 레이어 (socat): 시리얼 바이트를 소켓용 네트워크 스트림으로 가공

    ↓ (로컬 TCP 루프백 포트 8999 바인딩)

    ③ 보안/터널 계층 (SSH Tunnel): 데이터를 외부 공격으로부터 보호하기 위해 암호화 터널링

    ↓ (SSH 패킷으로 포장)

    ④ 전송 계층 (TCP/IP & 물리 LAN): 사설 IP(192.168.x.x) 대역의 스위칭 허브 및 이더넷 케이블 통

     

     

    [수신단: 서버 K (Kepler)]

    ④ 전송 계층 (TCP/IP & 물리 LAN): 암호화된 SSH 패킷 수신

    ③ 보안/터널 계층 (SSH Tunnel): SSH 프로토콜 단에서 패킷 암호화 해제 (복호화)

    (지정된 포트 대기 상태인 소켓으로 전달)

    ② 직렬화/중계 레이어 (socat): 네트워크 스트림을 다시 가상 시리얼 데이터로 복원

    (가상 터미널 인터페이스: /tmp/vtty1 장치 파일에 밀어넣기)

    ① 응용 레이어 (MATLAB): 수신 버퍼에서 RS-232 데이터 패킷 최종 수신 및 GNSS 필터 연산

     

     

     

    개념 설명이 길어졌는데(원래 잘 모를 수록 많이 적어야한다 ㅎ.ㅎ.), 그럼 이 socat을 실제로 구현하는 것은 어렵지 않다. 

     

    (1) K에서 소켓 열기(socat 대기) 

     

    socat TCP-LISTEN:4001,reuseaddr PTY,link=/tmp/vtty1,mode=777 &

     

    • TCP-LISTEN: TCP 프로토콜을 사용하여 네트워크 상의 4001번 포트를 읽어들이겠다는 뜻
    • reuseaddr: 프로그래밍이나 통신이 비정상으로 종료되었을 때, 포트 충돌 에러를 막기 위해 프로세스가 종료되었더라도 대기 시간 없이 포트를 재사용하겠다는 뜻
    • PTY: 리눅스 커널에게 Pseudo-Terminal을 메모리에 생성해달라고 요청하는 명령어
    • PTY가 가상 장치를 생성하면 이를 /tmp/vtty1이라는 이름의 Symlimk파일로 연결요청하는 코드
    • mode=777, 리눅스 파일 권한 설정으로 모든 사용자에게 최고 권한 부여

     

    (2) P-K간 22포트 말고 다른 포트 만들기(ssh 터널링) 

    ssh -L 4001:localhost:4001 ejl@[K의 IP주소]
    • -L(Local Port Forwarding/로컬 포트 포워딩) 

     

    (3) P에서 소켓 열기(socat 접속 및 파일 바인딩) 

    socat PTY,link=/tmp/vtty0,mode=777 TCP:127.0.0.1:4001 &
    • TCP: 해당 주소로 CONNECT하겠다 
    • 127.0.0.1:4001 - 내 컴퓨터 로컬의 4001포트로 접속 
    • &으로 백그라운드 실행을 했는데, &없이 실행해도 된다(다만, 해당 터미널 창은.. 사용할 수가 없겠지..) 

     

    💡 그리고 중간중간 포트가 생성되었나 - 하고 확인을 해봤는데 3단계를 완료하기 전까지는 포트가 조회되지 않는다. 그러니 꼭 3단계를 뫃두 거친 뒤에 확인/디버깅을 진행하도록 하자 !! 

     

    💡 Serial Port를 사용하거나, ssh Port를 사용하다보면 가끔 꼬이는 경우가 있다. 그럴 때를 위해 socat, port를 닫는 방법이다. 

    # check port 
    ss -ant | grep 4001 
    
    # close port 
    lsof -i :4001
    
    #kill socat 
    killall -9 socat

     

     

    어쨌든 교수님께서 요청하신 .. RS-232를 SW적으로 구현하는 것에 성공했다(=이제 집에갈 수 있다) 

    그럼 이렇게 연결을 해서 뭘 할거냐 !!는 다음 시간 매트랩 구현하는 과정에서 .. 

     

     

     

     

     

Designed by Tistory.