2024-08-07 (TIL)

SanE·2024년 8월 7일
0

컴퓨터공학

목록 보기
21/23

👨🏻‍💻학습 내용


💡 소켓 통신

소켓(Socket)?

소켓 (Socket)은 소프트웨어로 작성된 추상적인 개념으로 네트워크 상 두 프로그램 간의 엔드포인트이다.
쉽게 말하면 네트워크 상에서 데이터를 주고 받는 창구 역할을 한다고 보면 되며, 소켓은 IP주소와 포트 번호의 조합으로 식별된다.

소켓 통신 동작

이미지 출처 - https://sparcs.org/blog/how-to-use-websocket/

  1. 소캣 생성 : 서버와 클라이언트 모두 소캣을 생성.
  2. 바인딩 : 서버는 특정 IP 주소와 포트 번호에 바인딩한다.
  3. 연결 대기 : 서버는 연결 요청을 기다린다.
  4. 연결 요청 : 클라이언트가 서버의 IP와 포트 번호로 연결 요청.
  5. 연결 수락 : 서버가 클라이언트의 연결 요청을 수락.
  6. 데이터 통신 : 연결이 설정되면 양방향으로 데이터를 주고 받는다.
  7. 연결 종료 : 통신이 완료되면 소켓을 닫는다.

HTTP 통신 ?

HTTP는 이전 포스트를 통해 설명했기 때문에 간단히 설명하겠다.

HTTP는 Hypertext Transfer Protocol의 약자이며 웹에서 정보를 주고 받기 위한 프로토콜이다.
HTTP 통신은 기본적으로 요청 / 응답으로 이루어진다.

HTTP 통신 동작

이미지 출처 - https://sparcs.org/blog/how-to-use-websocket/

  1. 연결 설정 : 클라이언트가 서버와 TCP 연결을 설정. (일반적으로 HTTP는 80번, HTTPS는 443번 포트 이용)
  2. 요청 생성 : 클라이언트가 HTTP Request Message를 생성.
  3. 요청 전송 : 클라이언트가 만들어진 메시지를 전송.
  4. 요청 처리 : 서버가 요청을 처리.
  5. 응답 생성 : 서버가 HTTP Response Message를 생성.
  6. 응답 전송 : 서버가 만들어진 메시지를 전송.
  7. 응답 처리 : 클라이언트가 응답을 처리한다.
  8. 연결 종료 : 응답 - 요청 주기 완료 후 연결 종료. (HTTP/1.1 이상에서는 Keep-Alive 헤더를 이용해 연결 유지 가능)

HTTP Message에 관한 자세한 설명은 이전 포스트 참고

각 통신별 특징

소켓 통신

  • 양방향 통신 : 클라이언트와 서버가 실시간으로 데이터를 주고 받는다.
  • 연결 지향적 : 한 번 연결을 설정하면 지속적인 통신이 가능.
  • 실시간 통신 : 데이터를 즉시 주고 받기 때문에 실시간 서비스에 적합.

HTTP 통신

  • 요청-응답 구조 : 클라이언트의 요청에 대해 서버가 응답하는 단방향 통신이다.
  • 비연결성 : 각 요청은 독립적이고 서버는 클라이언트의 이전 요청을 기억하지 않는다.
  • 무상태 : 각 요청 간에 상태 정보를 유지하지 않는다.

차이점

  1. 연결 방식:

    • HTTP: 비연결성으로, 요청-응답 후 연결 종료.
    • 소켓: 연결 지향적으로, 지속적인 연결 유지.
  2. 통신 방향:

    • HTTP: 주로 단방향 통신 (클라이언트 요청 → 서버 응답).
    • 소켓: 양방향 통신 가능.
  3. 실시간성:

    • HTTP: 실시간 통신에 제한적.
    • 소켓: 실시간 데이터 교환에 적합.
  4. 상태 유지:

    • HTTP: 무상태 프로토콜로, 각 요청은 독립적.
    • 소켓: 연결 상태를 유지하며 지속적인 통신 가능.
  5. 리소스 사용:

    • HTTP: 요청-응답 후 연결 종료로 리소스 사용 효율적.
    • 소켓: 지속적 연결로 더 많은 서버 리소스 사용.
  6. 사용 사례:

    • HTTP: 웹 페이지 로딩, RESTful API 등.
    • 소켓: 실시간 채팅, 온라인 게임, 실시간 협업 도구 등

정리

HTTP 통신은 웹 페이지 로딩과 RESTful API에 사용되며 리소스 사용이 효율적이라는 장점이 있다. 그러나 실시간 통신이나 반복적인 통신의 경우 비효율적인데 소켓 통신의 이점은 이 때 드러난다.

소켓 통신은 실시간 통신이 가능하고 무엇보다도 서버 -> 클라이언트 방향으로 먼저 정보를 전송하는게 가능하다.
따라서 소켓 통신은 실시간 채팅이나 온라인 게임등 실시간 정보 전달이 중요한 서비스에서 이용된다.

💡 Echo 서버 : 소켓 프로그래밍의 기초

Echo 서버 ?

Echo 서버는 클라이언트로부터 받은 메시지를 그대로 다시 클라이언트에게 돌려주는 서버이다.

이런걸 학습하는게 무슨 의미가 있을까?

그 이유는 바로 Echo 서버는 소켓 통신의 기본을 이해하는데 매우 유용하다.

2. Echo 서버의 동작

Echo 서버의 동작은 앞서 말했던 소켓 통신의 동작과 완벽히 똑같다.

  1. 서버 소켓 생성: 서버는 소켓을 생성하고 특정 IP 주소와 포트 번호에 바인딩.
  2. 연결 대기: 서버는 클라이언트의 연결 요청을 대기.
  3. 연결 수락: 서버가 클라이언트의 연결 요청을 수락.
  4. 데이터 수신 및 송신: 서버는 클라이언트로부터 받은 데이터를 그대로 다시 클라이언트에게 전송.
  5. 연결 종료: 클라이언트와 서버가 통신을 종료하면 소켓을 닫는다.

Node.js를 사용한 Echo 서버 구현

Node.js는 비동기 이벤트 기반의 자바스크립트 런타임으로, 소켓 프로그래밍에 매우 적합합니다. Node.js의 net 모듈을 사용하여 Echo 서버를 구현해 보겠습니다.

Client 코드

const net = require('net');
const readline = require('readline');

// 소켓 생성.
const client = new net.Socket();
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

// 2024는 서버가 리스팅하는 포트 번호
// 0,0,0,0는 모든 네이트워크 인터페이스 (로컬 호스트의 경우 "localhost" 또는 "127.0.0.1"을 사용.
client.connect(2024, '0.0.0.0', () => {
	// readline을 이용해서 사용자 입력을 기다리기 위해 prompt사용.
    rl.prompt();
});

// 서버에서 보낸 데이터를 받는 부분.
client.on('data', (data) => {
    console.log(data.toString());
    rl.prompt();
});

// 종료 시켰을 때 이벤트
client.on('close', () => {
    console.log('서버와 연결 종료');
    rl.close();
});

// 입력을 서버로 보내는 부분.
rl.on('line', (input) => {
  // 0을 입력하면 접속 종료.
    if (input === "0") client.destroy();
    client.write(input);
});

rl.on('close', () => {
    client.destroy();
});

Server 코드

const net = require('net');

class EchoServer {
  
    constructor(port) {
        this.port = port;
        // 서버가 생성될 때마다 (socekt)=>{} 콜백 실행.
        this.server = net.createServer((socket) => this.handleConnection(socket));
    }

    start() {
      // 0,0,0,0 으로 설정해서 모든 네트워크 인터페이스에서 받는다.
        this.server.listen(this.port, '0.0.0.0', () => {
            // 서버가 시작할 때 사용 될 콜백 
          	// 이부분에 콘솔을 출력하면 서버가 시작되면 콘솔을 출력한다.
        });
    }

    handleConnection(socket) {
      // ip 주소는 socket.remoteAddress
      // 포트 번호는 socket.remotePort

        // 연결을 활성상태로 유지
        socket.setKeepAlive(true);
        // 데이터를 즉시 전송
        socket.setNoDelay(true);


        // 클라이언트가 보낸 데이터 처리 부분.
        socket.on('data', (data) => {
            // data를 통해 서버에 정보가 온다.
          	// data.toString()을 통해 문자열로 바꿔서 출력하면 출력 된다.
          const input = data.toString().trim();
          // 이부분을 통해 다시 클라이언트에게 전달.
          socket.write(input + "\n");
          // 전달 후 종료.
          socket.end();
        });

        socket.on('end', () => {
            // 종료시 콜백 코드
        });

        socket.on('error', (err) => {
            // 에러 발생시 콜백 코드
        });
    }
}

const server = new EchoServer(2024);
server.start();

Echo 서버 테스트

  1. 서버 실행: 서버 코드를 실행하여 Echo 서버를 시작합니다.

    node server.js
  2. 클라이언트 실행: 클라이언트 코드를 실행하여 서버에 연결하고 메시지를 전송합니다.

    node client.js

TELNET을 이용해서 telnet [IP or Domain] [port] 명령을 터미널에 입력해서 실행시킬 수도 있다.

  1. 결과 확인: 서버와 클라이언트의 콘솔 로그를 통해 메시지가 제대로 송수신되는지 확인합니다.

참고 자료

Socket 통신 & HTTP 통신

TCP 기반 서버 / 에코 서버

TELNET

profile
완벽을 찾는 프론트엔드 개발자

0개의 댓글