nodejs의 net 모듈을 이용하여 http서버를 구축하고 클라이언트와 서버간 데이터 통신을 이해하기 위한 프로젝트
1. const { createServer, Socket } = require('net'); // // http서버 구축을 위한 net모듈
2. const path = require('path'); // path의 조합을 path모듈
3. const js = require('fs') // 해당 디렉토리 여부, 파일의 생성/수정/삭제/읽기 등을 위한 fs모듈
4. const port = 3030; // 서버의 기본 포트 번호
client에서 Request(요청)이 오면 내부 로직에 의해 Response(응답)처리
client에서 connect로 접속하면 이 Listener로 Socket Client가 들어오는 형태
const server = createServer(client) {
client.on('data', (data) => {
// client에서 write()를 하면, 이곳을 통해 메세지를 받아 write()를 해준다
// 여기에 Response(응답) 로직 구현
});
};
해당 포트에서 수신을 대기하는 서버를 만듬
server.listen(port, () => {});
// ---------------------------------------------
// client
// ---------------------------------------------
const client = new Socket(); // Socket을 생성
client.connect(port, 'localhost', () => {}); // 포트, url로 접속
client.on('data', serverData => {
// server에서 write()하여 보내준 데이터를 이곳에서 처리
client.destroy();
});
이 프로젝트를 진행 하면서 발생했었던 문제
- 요청, 응답, Header, Body등 HTTP 통신을 제대로 이해하지 못한 상태로 프로젝트를 진행하다 보니 서버에서 요청이나 응답을 할 때 어떤식으로 보내야 하는지에 대한 로직 구현의 어려움이 발생
- 링크의 확장자가 없는 상태에서 클라이언트(브라우저) 요청이 오는데 해당 확장자를 파싱할 수 있는 방법을 알지 못해 로직내부에 하드코딩
- 언제 어떤파일이 요청으로 을지 모르는 상태에서 하드코딩을 해놓은 상태라 파일이 동적으로 추가될 때 마다 동일한 양의 로직이 생성됨
- 이해도가 없는 상태에서 기능구현에만 초점을 맞춰 읽기도 불편하고 엉망진창임
이 외에도 무수히 많은 문제점이 있겠지만 직접 느낀 문제점들만 나열..
아래는 Server/Client 전체 로직
// ---------------------------------------------
// server
// ---------------------------------------------
const { createServer, Socket } = require('net');
const path = require('path');
const fs = require('fs');
const port = 3030;
const server = createServer((clientSocket) => { // 2
clientSocket.on('data', (data) => { // 4
// buffer 데이터 > string 데이터로 변경
const requestMessage = data.toString();
// 요청온 데이터 중 첫번 째 줄(메소드, URI, 버전) 따로 변수에 저장
const [first] = requestMessage.split('\r\n');
// 각각의 변수명으로 저장
let [method, resource, version] = first.split(' ');
// 만약 URI가 "/"값이면 index.html 넣어줌
if (resource[resource.length - 1] === "/") {
resource += 'index';
}
const file = resource.split("/");
const fileName = file.pop();
console.log("파일명 >>>>>>> ", fileName);
const filePath = file.join("/");
console.log("폴더명 >>>>>>>", filePath);
const fullPath = path.join(process.cwd(), filePath);
try {
if (fileName === "index") { // index 페이지
const content = fs.readFileSync(path.join(fullPath, 'index.html')); // 동기
clientSocket.write(Buffer.from(`HTTP/1.1 200 OK\r\n`));
clientSocket.write(Buffer.from(`Content-Type: text/html\r\n`));
clientSocket.write(Buffer.from(`Content-Length: ${content.length}\r\n`));
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.write(content);
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.end();
}
else if (fileName === "what_to_eat") { // what_to_eat 페이지
const content = fs.readFileSync(path.join(fullPath, 'what_to_eat.html')); // 동기
clientSocket.write(Buffer.from(`HTTP/1.1 200 OK\r\n`));
clientSocket.write(Buffer.from(`Content-Type: text/html; text/javascript;\r\n`));
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.write(content);
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.end();
}
else if (fileName === "randomMenu") {
const content = require(path.join(fullPath, 'randomMenu.js')).getmenu();
clientSocket.write(Buffer.from(`HTTP/1.1 200 OK\r\n`));
clientSocket.write(Buffer.from(`Content-Type: text/plain;\r\n`));
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.write(content);
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.end();
}
else if (fileName === "error500") {
require(path.join(process.cwd(), '/server/', 'error.js')).geterror();
}
else {
// 404 error
const content = `
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>404 Error</h1>
</body>
</html>
`;
clientSocket.write(Buffer.from(`HTTP/1.1 404 ${resource} is not found\r\n`));
clientSocket.write(Buffer.from(`Content-Type: text/html\r\n`));
clientSocket.write(Buffer.from(`Content-Length: ${content.length}\r\n`));
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.write(content);
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.end();
}
}
catch (error) {
console.log(error);
const content = `
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>${error}</h1>
</body>
</html>
`;
clientSocket.write(Buffer.from(`HTTP/1.1 500 Internal Server error\r\n`));
clientSocket.write(Buffer.from(`Content-Type: text/html\r\n`));
clientSocket.write(Buffer.from(`Content-Length: ${content.length}\r\n`));
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.write(content);
clientSocket.write(Buffer.from(`\r\n`));
clientSocket.end();
}
});
});
server.listen(port, () => {
console.log(`Server Listen`);
});
// ---------------------------------------------
// client
// ---------------------------------------------
const client = new Socket();
client.connect(port, 'localhost', () => {});
client.on('data', serverData => {
console.log(`[client] data >>>>>> `, serverData);
client.destroy();
});
Git URL - https://github.com/jungcolor/app_project/tree/main/tcp-socket-exercises