server와 clinent로 폴더를 분리했다.
server는 localhost:8080포트
사용
clinen는 localhost:3000포트
사용
express, socket.io 패키지를 설치한 후 app.js파일에 서버를 만들고 socket.io와 연결했다.
// app.js
const express = require("express"); // express모듈 불러오기
const app = express(); // app변수에 express인스턴스 반환
const http = require("http");
const server = http.createServer(app); // 웹서버(객체) 생성
const port = 8080;
app.get("/", (req, res) => {
res.send("Hello World!");
});
server.listen(port, () => {
console.log(`서버가 실행됩니다. http://localhost:${port}`);
});
http모듈
express모듈
http모듈 외에 express를 사용하는 이유
http모듈만으로 라우팅을 처리하려면 조건문으로 일일이 복잡하게 구현해야한다.
express를 같이 사용하면 다양한 라이브러리와 미들웨어가 제공되어 편리하게 개발할 수 있다.(라우팅, 모듈화, 다양한 기능들...)
// http모듈만 사용했을 경우
const http = require('http')
const { sendPosts } = require('./sendPosts')
const server = http.createServer((req, res) => {
const { url, method } = req
res.setHeader('Content-Type', 'application/json')
if (url === '/') return res.send({ message: '/ endpoint' })
if (url === '/signup' && method === 'POS') return res.end(JSON.stringify({ message: '회원가입 완료!' }))
if (url === '/login' && method === 'POST') return res.end(JSON.stringify({ message: '로그인 완료!' }))
if (url === '/products' && method === 'GET') return sendPosts(res)
res.send(JSON.stringify({ message: 'this response answers to every request' }))
})
server.listen(8080, () => { console.log('server is listening on PORT 8000')})
// express와 함께 사용한 경우
const http = require('http')
const express = require('express')
const { sendPosts } = require('./postings')
const app = express()
app.use(express.json())
app.get('/', (req, res) => {
res.json({ message: '/ endpoint' })
})
app.post('/signup', handleSignUp)
app.post('/login', handleLogin)
app.get('/products', sendPosts)
const server = http.createServer(app)
server.listen(8000, () => {
console.log('server is listening on PORT 8000')
})
https://quark21.tistory.com/m/331
https://velog.io/@hahan/Http-%EB%AA%A8%EB%93%88%EA%B3%BC-Express-%EB%AA%A8%EB%93%88%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90
https://abc1211.tistory.com/m/225
io 객체 - 연결된 전체 클라이언트들과의 interacting을 위한 객체이다.
socket 객체 - 개별 클라이언트와의 interacting을 위한 객체이다.
on메소드
io.on
: 소켓 서버에 일어나는 이벤트를 수신해 핸들러를 실행시키기 위한 메소드이다. socekt.io
: 접속되어 있는 클라이언트로부터의 이벤트+데이터를 수신하기 위한 메소드이다. emit메소드
io.emit
: 연결되어있는 모든 클라이언트에게 이벤트+데이터를 발송하기 위한 메소드이다.socket.emit
: 접속되어 있는 클라이언트에게 이벤트+데이터를 발송하기 위한 메소드이다.*클라이언트와 서버 간에 주고 받는 이벤트 이름은 같아야 한다.
// app.js
const express = require("express");
const app = express();
const http = require("http");
const server = http.createServer(app);
const io = require("socket.io")(server);
const port = 8080;
app.get("/", (req, res) => {
res.send("Hello World!");
});
// 클라이언트가 접속할 떄 소켓 서버에 connection이벤트가 발생하고 이벤트를 일으킨 socket이 전달된다.
io.on("connection", (socket) => {
console.log("user connected");
// 접속한 클라이언트의 정보가 수신되면
socket.on("login", (data) => {
console.log(
"Client logged-in:\n name:" + data.name + "\n userid: " + data.userid
);
// socket에 클라이언트 정보를 저장한다
socket.name = data.name;
socket.userid = data.userid;
// 접속된 모든 클라이언트에게 메시지를 전송한다
io.emit("login", data.name);
});
socket.on("message", (data) => {
console.log(data.message);
const responseMsg = {
msg: data.msg,
};
// 접속된 모든 클라이언트에게 메시지를 전송한다
io.emit("message", responseMsg);
});
socket.on("disconnect", () => {
console.log("user disconnected");
});
});
server.listen(port, () => {
console.log(`서버가 실행됩니다. http://localhost:${port}`);
});
*클라이언트와 서버 간에 주고 받는 이벤트 이름은 같아야 한다.
// _app.tsx
import "../styles/globals.css";
import io from "socket.io-client";
import { useEffect } from "react";
// 앱 실행 시 통신하려는 서버와 연결, soceket인스턴스 반환
const socket = io("http://localhost:8080");
// soceket통신 시 발송되어야 할 이벤트와 데이터 등록
function MyApp({ Component, pageProps }) {
const handleLogin = () => {
socket.emit("login", {
name: "yy2122",
userid: "0",
});
};
const handleSendMessage = (mes) => {
socket.emit("message", { msg: mes });
};
// socket통신 시 수신되어야 할 이벤트와 핸들러 등록
useEffect(() => {
socket.on("connect", () => {
console.log("SOCKET CONNECTED!", socket.id);
});
socket.on("login", (data) => {
console.log(data);
});
socket.on("message", (data) => {
console.log(data.msg);
});
socket.on("disconnect", () => {
console.log("서버와 연결이 해제되었습니다.");
});
// 앱 종료 시 등록한 이벤트 해제
return () => {
socket.off("connect");
socket.off("disconnect");
socket.off("login");
socket.off("message");
};
}, []);
return (
<>
<Component {...pageProps} />
<button onClick={handleLogin}>로그인</button>
<button
onClick={() => {
handleSendMessage("메세지!!");
}}
>
메세지 전송
</button>
</>
);
}
export default MyApp;
위에 작성한 코드들로 실행했을 때 cors오류가 발생했다.
클라이언트와 서버의 포트가 달라서이다.
해결
소켓 서버 생성 시 cors관련 옵션을 전달해주어 해결했다.
// server - app.js
const express = require("express");
const app = express();
const http = require("http");
const server = http.createServer(app);
const io = require("socket.io")(server); // cors발생 코드
const port = 8080;
// cors관련 옵션 추가한 코드
const io = require("socket.io")(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});