다음은 앞서 설명했던 단계들이 socket.io에서 어떻게 구현되어 있는지를 알아보겠다.
클라이언트단은 React.js 서버단은 Node.js를 사용하였다.
1. 소켓 생성
: 클라이언트는 socket.io-client에서 server의 IP와 port를 넣고 변수를 생성하면 된다.
클라이언트 - socket()
//./component/socket.js
import React from 'react';
import io from "socket.io-client";
// import { SOCKET_URL } from "config";
export const socket = io('localhost:5000');
export const SocketContext = React.createContext();
: 서버는 socket.io에서 http server를 인식시키고, port를 선택하여, 요청을 listen한다.
서버 - socket(), bind(), listen()
// server.js
const server = require('http').createServer(app);
const io = require('socket.io')(server, {cors : {origin : "*"}});
const port = process.env.PORT || 5000;
io.listen(port, () => {
console.log('Server listening at port %d', port);
});
2. 연결, 연결 해제 및 데이터 전송
클라이언트 : emit(), on()
서버 : emit(), on()
1. client로 부터 username과 함께, 'add user'로 접근한다.
//client
useEffect(async() => {
socket.emit('add user', nickname);
...
});
2. io.on('connection', (socket) => { ... }) 에서 연결을 처리하며, numUsers와 socket의 임의의 parameter인 username을 붙여서 관리한다.
//server.js
io.on('connection', (socket) => {
let addedUser = false;
// when the client emits 'add user', this listens and executes
socket.on('add user', (username) => {
if (addedUser) return;
// we store the username in the socket session for this client
socket.username = username;
++numUsers;
console.log("connected : "+socket.id+" num : "+numUsers);
addedUser = true;
socket.emit('login', {
numUsers: numUsers
});
// echo globally (all clients) that a person has connected
socket.broadcast.emit('user joined', {
username: socket.username,
numUsers: numUsers
});
});
3. 요청받은 request를 처리하고, emit을 통해서, response 하면, client에서는 on을 통하여, 그에 해당하는 동작들을 실행한다.
//client
useEffect(async() => {
socket.emit('add user', nickname);
socket.on('login', (data) => {
setIsConnected(true);
addChatMessage(data);
});
socket.on('user joined', (data) =>{
setchats(chats.concat(`${data.username} joined`));
})
});
4. client에서 새로운 Msg를 'new message'로 전달하면, broadcast 명령을 통해서, msg를 전달한 client를 제외한 나머지 socket에 msg를 emit 해준다.
//client
const sendMessage = () => {
console.log(Msg);
setchats(chats.concat(`${nickname} : ${Msg}`));
socket.emit('new message', Msg);
setMessage('');
}
useEffect(async() => {
socket.on('new message', (data) => {
setchats(chats.concat(`${data.username} : ${data.message}`));
});
return () => {
socket.off('login');
socket.off('disconnect');
socket.off('new message');
};
});
io.on('connection', (socket) => {
// when the client emits 'new message', this listens and executes
socket.on('new message', (data) => {
console.log(`${socket.username} : ${data}`);
// we tell the client to execute 'new message'
socket.broadcast.emit('new message', {
username: socket.username,
message: data
});
});
...
}
최종 코드
클라이언트
const Home = () => {
const location = useLocation();
const nickname = location.state.nickname;
const [chats, setchats] = useState([]);
const [isConnected, setIsConnected] = useState(socket.connected);
const [Msg, setMessage] = useState(null);
const addChatMessage = (data) => {
let message = '';
if (data.numUsers === 1) {
message += `there's 1 participant`;
} else {
message += `there are ${data.numUsers} participants`;
}
setchats(chats.concat(message));
}
useEffect(async() => {
socket.emit('add user', nickname);
socket.on('login', (data) => {
setIsConnected(true);
addChatMessage(data);
});
socket.on('user joined', (data) =>{
setchats(chats.concat(`${data.username} joined`));
})
socket.on('user left', (data) => {
setchats(chats.concat(`${data.username} left`));
});
socket.on('disconnect', () => {
setIsConnected(false);
});
socket.on('new message', (data) => {
setchats(chats.concat(`${data.username} : ${data.message}`));
});
return () => {
socket.off('login');
socket.off('disconnect');
socket.off('new message');
};
});
const sendMessage = () => {
console.log(Msg);
setchats(chats.concat(`${nickname} : ${Msg}`));
socket.emit('new message', Msg);
setMessage('');
}
const onChange = (e) =>{
setMessage(e.target.value);
}
return (
<div className="App">
<header className="App-header">
<p>Connected: { '' + isConnected }</p>
<p>socket ID: {nickname+`(${socket.id})` }</p>
<div className="scrollBlind">
<ul class ="message">
{chats.map((val, index) => {
return (<li key={index}>{val}</li>);
})}
</ul>
</div>
<div>
<input
onChange={onChange} value={Msg} class="inputMessage"
placeholder="Type here..."
onKeyPress={(e)=>{
if (e.key === 'Enter')
sendMessage();
}}/>
<button onClick={sendMessage} >Send</button>
</div>
</header>
</div>
);
};
export default Home;
서버
// Routing
app.use(express.static(path.join(__dirname, 'public')));
// Chatroom
let rooms = ["room1", "room2", "room3"];
let numUsers = 0;
io.on('connection', (socket) => {
let addedUser = false;
// when the client emits 'new message', this listens and executes
socket.on('new message', (data) => {
console.log(`${socket.username} : ${data}`);
// we tell the client to execute 'new message'
socket.broadcast.emit('new message', {
username: socket.username,
message: data
});
});
// when the client emits 'add user', this listens and executes
socket.on('add user', (username) => {
if (addedUser) return;
// we store the username in the socket session for this client
socket.username = username;
++numUsers;
console.log("connected : "+socket.id+" num : "+numUsers);
addedUser = true;
socket.emit('login', {
numUsers: numUsers
});
// echo globally (all clients) that a person has connected
socket.broadcast.emit('user joined', {
username: socket.username,
numUsers: numUsers
});
});
// when the client emits 'typing', we broadcast it to others
socket.on('typing', () => {
socket.broadcast.emit('typing', {
username: socket.username
});
});
// when the client emits 'stop typing', we broadcast it to others
socket.on('stop typing', () => {
socket.broadcast.emit('stop typing', {
username: socket.username
});
});
// when the user disconnects.. perform this
socket.on('disconnect', () => {
if (addedUser) {
--numUsers;
console.log("disconnected : "+socket.id+" num : "+numUsers);
// echo globally that this client has left
socket.broadcast.emit('user left', {
username: socket.username,
numUsers: numUsers
});
}
});
});
실행화면
소스코드
https://github.com/geun9716/node-multiroom-chat
'프로젝트 > UNY' 카테고리의 다른 글
socket.io 실시간 chat API 서버 (Node.js, Socket.io, Redis) (0) | 2022.04.20 |
---|---|
socket.io 실시간 chat 구현 (react - Node.js) - (1) (0) | 2021.07.08 |
CI board 와 xampp 로컬 설정 (0) | 2021.07.05 |