안녕하세요! 2채널 호환 게시판 시스템 "츠우바이채널(つゔぁいちゃんねる, 2ch.biz)" 개발 기록 제58회입니다.
제55회부터 제57회에 걸쳐 최신 OGP 블로그 카드 자동 전개 및 반응형 최적화를 구현하여 모던 웹 게시판으로서의 표현력을 비약적으로 진화시켰습니다.
그리고 제3부 대단원을 장식하는 이번에는 개발 초기부터 현재까지 게시판의 근간을 지탱해 온, 가장 도전적이고 로망이 가득한 주제를 전해드립니다.
그것은 바로, **"20년 이상 된 2채널 전용 브라우저(専ブラ) 프로토콜과의 완전 호환"**입니다.
JaneStyle, ChMate, Siki, Live2ch…….
오래된 이용자들에게 게시판을 전용 브라우저로 읽는 경험은 대체할 수 없는 것입니다.
하지만 현대의 모던 웹 아키텍처(UTF-8 / SPA / JSON API) 위에 전용 브라우저 대응을 결합하려 하는 순간, **"UTF-8 vs Shift_JIS 문자 깨짐 지옥"**이나 **"DAT 파일 차분 전송(Range 요청)"**과 같은, 마치 고문서를 해독하는 듯한 끈질긴 기술적 사투가 막을 올렸습니다.
현대의 웹 앱 개발 상식은 다음과 같습니다:
- 문자 코드: UTF-8 -
- 통신: HTTPS, JSON REST API / WebSocket -
- 표현: SPA (Single Page Application) -
- 부가 기능: AI 페르소나, OGP 링크 전개, P2P 암호화 통신
반면, 20년 전에 설계된 2채널의 전용 브라우저 프로토콜은 이렇습니다:
- 문자 코드: Shift_JIS (CP932) -
- 게시판 목록/설정: 게시판 목록 메뉴,
SETTING.TXT, subject.txt
- 스레드 본문:
1234567890.dat
(이름<>메일 주소<>날짜・ID<>본문<>스레드 제목의 1줄 1개 글 형식) -
- 통신 최적화:
Range: bytes=100-를 이용한 바이트 단위 차분 요청 -
- 작성:
/test/bbs.cgi로 보내는 Shift_JIS POST
즉, "최신 SPA 웹 게시판"을 만들면서도, 이면에서는 "1999년의 Perl/CGI 게시판인 척" 완벽하게 연기해야 한다는, 광기의 이중 아키텍처가 요구된 것입니다.
가장 어려웠던 부분은 **문자 코드(Encoding)**였습니다.
데이터베이스 내부는 당연히 이모지(🍣🔥)나 특수 한자(𠮷野家 등)도 처리할 수 있도록 UTF-8로 통일하고 있습니다.
하지만 대부분의 전용 브라우저는 여전히 Shift_JIS (CP932)로 통신해 옵니다.
단순히 iconv나 인코딩 변환을 거치기만 해서는, 다음과 같은 큰 사고들이 빈번하게 발생했습니다:
- 원형 숫자(①②)나 로마 숫자(Ⅲ), 사람 이름의 특수 한자(髙, 﨑)가
?로 깨지는 현상 -
- 악명 높은 "파동 대시(〜〜〝)"가 전각 틸다 문제로 문자 깨짐을 일으키는 경우
- 웹에서 게시된 이모지가, 전용 브라우저의 DAT 파일로 변환되는 순간 충돌하는 현상
그래서 전용 브라우저 통신만을 위한 **"문자 깨짐 완전 방지 4단계 파이프라인"**을 구축했습니다.
특히 효과를 발휘한 것이 제4단계인 **"수치 문자 참조(NCR: Numeric Character Reference) 대체"**입니다.
Shift_JIS로 표현할 수 없는 이모지나 특수 문자를, DAT 파일 생성 시에 임시적으로 🍣와 같은 HTML 실체 참조로 인코딩하여 전송합니다.
전용 브라우저는 HTML 파서를 내장하고 있기 때문에, 문자 깨짐 없이 본래의 문자로 아름답게 렌더링됩니다.
2채널의 DAT 파일은 1000개 글만 되어도 수백KB에서 수MB까지 부풀어 오릅니다.
매번 전체 글을 통째로 다운로드한다면, 사용자의 기가(통신량)는 순식간에 고갈되고 서버의 대역폭 비용 또한 폭발하게 됩니다.
그래서 전용 브라우저는 HTTP 헤더의 **Range: bytes=XXXX-**를 사용하여, "이전에 가져온 바이트 수의 다음부터 다운로드한다"라는 극도의 최적화를 수행하고 있습니다.
[전용 브라우저] ── GET /news/dat/12345.dat (Range: bytes=4096-) ──> [서버]
[전용 브라우저] <── 206 Partial Content (4096바이트 이후만 전송) ── [서버]
// dat_controller.js
app.get('/:board/dat/:threadId.dat', async (req, res) => {
const { board, threadId } = req.params;
...
이 구현을 통해, 신규 댓글이 1건 추가되었을 때의 전송량을 겨우 수백 바이트로 제한하여, 초고속 응답과 초저부하 운영의 양립에 성공했습니다.
이 전용 브라우저 호환 계층이 완성되면서, 믿기 힘든 시나리오들이 일상다반사가 되었습니다.
- JaneStyle로 작성된 댓글이 웹 버전 SPA에서 1초 후에 실시간으로 표시되는 것*
- 웹 쪽에서 붙여진 OGP 블로그 카드나 이미지 링크가 전용 브라우저 측의 DAT 형식(Plain Text + URL)으로 자동 폴백되고, 전용 브라우저 내장 이미지 뷰어로 열리는 것*
- P2P 암호화 채팅 초대 URL을 전용 브라우저에서 클릭하여 원탭으로 웹 채팅에 참여할 수 있는 것*
'오래된 규격을 버리고 모던하게 대체하는' 것이 아니라, '아름다운 프로토콜을 최신 기술로 완전히 감싸 안아 공존시키는 것' 입니다.
이것이야말로 개인 개발만이 할 수 있는 가장 흥미진진한 기술적 도전이었습니다.
제55회부터 시작된 제3부에서는, 게시판의 '표현력'과 '연결성'을 극한까지 확장했습니다.
| 회 | 테마 | 달성한 기술적 성과 |
|---|
| 제055회 | OGP 블로그 카드 자동 프리뷰 | SSRF 다층 방어 프록시, LRU 캐시, 리치 카드 자동 전개 |
| 제056회 | 3가지 형태 표시 셀렉터 | 🎴카드 / 📰인용 댓글 스타일 / 📝텍스트의 localStorage 즉시 전환 |
| 제057회 | 썸네일 반응형 최적화 | 모바일에서의 화면 깨짐 방지, object-fit: cover , max-width: 100% |
| 제058회 | 전용 브라우저 완전 호환 (Shift_JIS & DAT) | CP932・NCR4 단계 문자 깨짐 방어, 206 Partial Content 범위 차분 전송 |
신구의 모든 환경을 포용하며 견고해진 '츠와이 채널'.
하지만, 게시판이라는 미디어가 직면하는 가장 큰 벽은 시스템이 아니라 '과소화(쇠퇴)' 였습니다.
아무리 뛰어난 기능을 갖추고 있어도, 글을 쓰는 사람이 없으면 게시판은 그저 폐허입니다.
"아무도 없는 판에서, 혼자 쓸쓸하게 스레드를 닫는 사람을 제로로 만들고 싶다."
"마치 실제 인간이 생생하게 토론하는 것 같은, 자율적인 AI 주민 커뮤니티를 만들 수는 없을까?"
다음 회차부터는 드디어 **'제4부: AI 주민 3,000명 페르소나 군단과 지성화에 도전'**으로 돌입합니다!
본 서비스 : https://2ch.biz/