1. HTTP vs TCP
HTTP는 비연결성 구조로 request가 없으면 response도 없다. 연결을 유지하지 않기때문에 많은 트래픽을 빠르게 처리가능합니다. 연결을 유지해야 하는 리소스를 아낄 수 있는 장점이 있다. 또한 stateless(무상태)를 특징으로 가진다. 이전에 일어났던 일(상태)를 저장하고 있지 않아 세션, 쿠키 등으로 해당 요청에 대한 정보를 임의로 저장해서 처리하곤 합니다. HTTP의 메세지 구조는 start-line, header, empty-line, message body로 이루어져 있고 헤더는 메세지에 필요한 모든 부가 정보를 가진다. key-value의 map구조를 가지고 있어 방대한 정보를 추가할 수 있다.
HTTP는 네트워크 7계층 중 application layer에 속하며, 메일을 전송하는 SMTP, 파일을 전송하는 FTP 또한 여기에 포함되는 프로토콜이다. 이 레이어는 결국 transport layer 위에서 동작하게 되고 당연히 HTTP는 TCP나 UDP 둘 중 하나의 연결을 통해 동작하게 된다. 이 TCP는 HTTP와 달리 연결지향성을 지녀 데이터교환을 할 때 무조건 연결을 가집니다. 즉, HTTP의 Req ↔ Res 가 발생할때 밑에서 TCP 연결이 이뤄지고, 이 연결을 3way-handshake라고 부른다.
TCP 통신은 양방향 통신(Full-Duplex) 구조로 서버가 접속 요청을 받기위해 소켓을 열고(Listen), 클라이언트는 소켓을 만들어 서버에 접속을 요청합니다.(Connect) 그리고 서버는 이 요청을 받아 클라이언트와 통신할 소켓을 따로 만들고(Accept) 소켓을 통해 서로 정보를 주고 받습니다.(Send/Receive) 그리고 통신을 마치면 소켓을 닫음으로써 통신이 마무리 됩니다.(Close)
2. Websoket : HTTP프로토콜 위에서 동작하는 실시간 양방향 통신 (Full-Duplex)
- 실시간 통신 : 연결이 활성화된 상태에서 빠르고 지속적인 메시지 교환을 허용합니다. 이로 인해 애플리케이션은 사용자에게 지연 없는 인터랙션을 제공할 수 있습니다.
- 양방향 통신 : 클라이언트와 서버가 동시에 서로에게 메시지를 보낼 수 있습니다. 이는 한 쪽이 다른 쪽의 메시지를 기다리지 않고도 독립적으로 메시지를 송수신할 수 있음을 의미합니다.
- 지속적 연결 : 웹소켓 연결이 수립되면, 그 연결은 클라이언트나 서버가 명시적으로 종료할 때까지 유지됩니다.
- 낮은 오버헤드 : 웹소켓은 데이터 패킷의 헤더가 매우 작기 때문에 오버헤드가 낮습니다. 이는 효율적인 네트워크 자원 사용을 가능하게 합니다.
- HTTP와의 호환성 : 웹소켓은 HTTP 포트(80과 443)를 통해 작동하기 때문에 기존 웹 인프라와 잘 통합됩니다. 웹소켓 연결은 HTTP 연결을 통해 초기화되며, 이후 전이중 통신 채널로 전환됩니다.
웹소켓의 연결방법은 TCP의 연결방법 (3-way-handshake)를 닮아있다.
웹소켓은 기본적으로 TCP 연결 위에서 작동하기 때문에, 웹소켓 연결을 시작하기 전에 TCP의 표준 연결 방법인 3-way handshake가 수행됩니다. 하지만 웹소켓은 이후에 추가적인 핸드셰이크 과정을 진행하여 웹소켓 특유의 연결을 완성합니다.
3. 웹소켓 프로젝트 세팅
- package.json 파일 생성
npm init -y
그리고 es6 이상의 문법을 사용할 수 있도록 그 파일에 “type”: “module” 옵션을 추가해준다.
- 설치 명령어
npm i express soket.io
- 데브 디펜던시 설치
npm install -D nodemon prettier
- 프리티어 셋팅값 공유
{
"singleQuote": true,
"semi": true,
"useTabs": false,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100,
"arrowParens": "always",
"orderedImports": true,
"bracketSpacing": true,
"jsxBracketSameLine": false
}
- app.js 엔트리포인트 파일을 만들고 package.json에 "main" 옵션을 app.js로 수정하고 script에 "dev": "nodemon src/app.js"를 추가한다.
// src/init/socket.js
import { Server as SocketIO } from 'socket.io';
const initSocket = (server) => {
const io = new SocketIO();
io.attach(server);
};
export default initSocket;
// app.js
import express from 'express';
import { createServer } from 'http';
import initSocket from './init/socket.js';
const app = express();
const server = createServer(app);
const PORT = 3000;
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
initSocket(server); // 소켓 추가
app.get('/', (req, res) => {
res.send('<h1>Hello World</h1>');
});
server.listen(PORT, async () => {
console.log(`Server is running on port ${PORT}`);
});
서버가 실행될 때 init이라는 폴더 내부에 코드들이 실행되기 때문에 이름을 이렇게 지었다. 그리고 app.js에 코드를 추가해 실행할 때 socket.io가 실행될 수 있게 한다. 이로써 웹소켓을 위한 개발환경 셋팅을 마쳤다.