요즘 진행하는 스터디에서 다음과 같은 과제가 생겼다.
아래 조건을 만족하는 간단한 chat program을 만들자. (필수)
1. TCP 서버와 클라이언트를 가장 자신이 있는 언어로 구현한다.
2. 콘솔 화면을 띄우면서 클라이언트 콘솔에서 메시지를 보내면 서버 콘솔에서 전달받은 메시지를 보여 준다.
key word: socket programming. TCP
추가: wire shark를 설치해서 클라이언트와 서버 간에 주고받은 패킷을 확인하여 TCP 3-way handshake를 더 깊이 있게 이해하는 것이 주 목표.
node.js + node.js에 내장된 net + 역시 내장된 readline을 사용하여 구현했다.
디렉토리 구조는 다음과 같다 :
chat-program/
├── server/
│ └── server.js
└── client/
└── client.js
폴더 구분 없이 간단하게 server.js와 clinet.js만 있어도 되지만, 일단 구분했다(정리는 처음부터 해야 쉽다)
server.js의 코드는 다음과 같다 :
// net 모듈 사용
const net = require('net')
// TCP 서버 생성
const server = net.createServer(socket => {
console.log('클라이언트와 연결되었습니다.')
// 클라이언트로부터 데이터를 받았을 때 처리하는 부분
socket.on('data', data => {
console.log('클라이언트로부터 메세지를 수신했습니다 :', data)
})
// 클라이언트와 연결이 끊겼을 때 처리하는 부분
socket.on('end', () => {
console.log('클라이언트와의 통신이 종료되었습니다')
})
})
// 서버를 특정 포트에서 대기 시킴
const port = 3000
server.listen(port, () => {
console.log('서버가 실행되었습니다')
console.log('포트 번호 :', port)
})
간단하다. 사실 연결이 끊겼을 때도 필요 없다. 그럼 더 간단해진다.
clinet.js의 코드는 다음과 같다 :
// net, readline 사용
const net = require('net')
const readline = require('readline')
// 서버의 IP 주소와 포트 번호를 설정
const serverIP = '127.0.0.1' // 서버 IP
const serverPort = 3000 // 서버 port
// TCP 소켓 생성
const socket = new net.Socket()
// 서버 연결
socket.connect(serverPort, serverIP, () => {
console.log('서버에 연결되었습니다')
// 사용자 입력을 받기 위한 인터페이스 설정
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
// 사용자 입력을 받아 서버로 전송
rl.on('line', input => {
socket.write(input) // 입력한 데이터를 서버로 전송
})
// 서버로부터 데이터 수신 시 처리하는 부분
socket.on('data', data => {
console.log('서버로부터 메세지를 수신하였습니다: ', data)
})
// 서버와의 연결이 끊겼을 때 처리하는 부분
socket.on('end', () => {
console.log('서버와의 통신이 종료되었습니다')
rl.close() // 사용자 입력 인터페이스를 닫음
})
})
결과물
띠용...
클라이언트에서 전송한 문자열을 서버에서 받을 땐 전혀 읽을 수가 없다. 읽는 주체가 컴퓨터라면 모를까...
그렇다. 내가 놓친 것이 있었다. data(채팅 내용) 전송 시 문자열 그대로 전송되지 않고 buffer 형태로 전송된다.
따라서 우리는 data를 toString()으로 변환해줄 필요성이 있다.
또한 이때 서버를 ctrl + c로 종료하면서 깨달은, 빼먹어버린 error handling도 추가한다 :
// 클라이언트로부터 데이터를 받았을 때 처리하는 부분
socket.on('data', data => {
const message = data.toString() // 받은 데이터를 문자열로 변환
console.log('클라이언트로부터 메세지를 수신했습니다 :', message)
})
// 서버에서 에러가 발생했을 때 처리하는 부분
socket.on('error', error => {
console.error('서버 에러가 발생했습니다: ', error)
})
결과물
에러 메세지가 잘 뜨고, 채팅 역시 잘 읽어지는 것을 확인했다.
근데 여기에 보너스로 trim()을 넣어 채팅 메세지의 앞, 뒤에 불필요한 공백이 붙는 상황을 피하면 더욱 좋겠다.
// 클라이언트로부터 데이터를 받았을 때 처리하는 부분
socket.on('data', data => {
const message = data.toString().trim() // 받은 데이터를 문자열로 변환 및 양쪽 공백을 제거
console.log('클라이언트로부터 메세지를 수신했습니다 :', message)
})
마지막 결과물
참고 글을 보니 socket.io 라이브러리를 사용하면 Websocket을 Wrapping해서 더욱 빠른 실시간 통신이 가능한 모양이다. 사실 많이 들어본 것 같다. socket.io...써본 것 같다....
그렇게 나는 다음 포스팅에 socket.io로 간단하게 구현한 내용을 이어가게 되었다...
참고
채팅서비스를 구현하며 배워보는 Websocket 원리 (feat. node.js)
본 포스팅에서는 Websocket 의 원리를 배우고, node.js 의 ExpressJS 프레임워크에서 Websocket 서버를 만들어 웹브라우저와 실시간 통신으로 간단한 채팅을 만드는 것을 목표로 한다. 1. Websocket 이란? 1-1.
hudi.blog
Net | Node.js v20.4.0 Documentation
Net# Source Code: lib/net.js The node:net module provides an asynchronous network API for creating stream-based TCP or IPC servers (net.createServer()) and clients (net.createConnection()). It can be accessed using: const net = require('node:net'); copy IP
nodejs.org
'공부 > TIL' 카테고리의 다른 글
[Nods.js] dgram을 이용한 UDP 채팅 서버 구현 (0) | 2023.07.15 |
---|---|
[Node.js] Socket.io를 이용한 TCP/IP chat program 구현 (0) | 2023.07.15 |
[모두의 네트워크] 9장 (무선 랜 이해하기) (0) | 2023.07.06 |
[Tistory 스킨 편집] hELLO 스킨 적용 시 첫번째 카테고리들만 펼치기 (0) | 2023.07.05 |
[vue.js + electron] electron:serve에서는 보이던 화면이 electron:build하면 안보일 때 해결 방법 (0) | 2023.07.03 |