솔직히 이것도 쉬워보이긴 한다.
먼저, 이제 클라이언트 쪽에서 데이터를 그냥 문자열이 아닌 json 형태로 보내야 한다.
거기에 nickname, message를 필드로 가지고 있다.
뭐 그냥 바로 해보자.
사실 별 문제는 없었다.
클 -> 서버로 가는 데이터가 버퍼로 와서 변환해 줬다.
먼저 일단, 클쪽에서 문자열인 데이터를 Json으로 바꿔보자.
$msgForm.addEventListener("submit", (e)=>{
e.preventDefault();
const $nickname = $msgForm.querySelector("#nickname");
const $message = $msgForm.querySelector("#message");
const data = {
nickname:$nickname.value,
message : $message.value
}
socket.send(JSON.stringify(data));
$message.value = "";
});
그냥 input의 값을 받아오고,
그것으로 객체를 만들어 준 다음,
JSON.stringify(data) 해서 그 데이터를 Json 형태의 문자열로 변환시킨다음 보냈다.
그럼 서버쪽에서
socket.on("message", (m)=>{
const data = m.toString('utf-8');
console.log(data);
for(const sc of sockets){
sc.send(m.toString('utf-8'))
}
});
버퍼데이터로 받는데, 우선 그걸 utf-8 형식의 문자열로 변환해 준다.
그 다음 그냥 그걸 그대로 보낸다.
내가 알기로 아마 전송간에 데이터는 다 문자열로만 가능한 걸로 안다.
그래서 문자열이지만 json형태인 저걸 그대로 보내면 된다.
그러면, 클라이언트 측에서,
socket.addEventListener("message", (m)=>{
const $li = document.createElement("li");
const $nickname = document.createElement("span");
const $message = document.createElement("p");
const data = JSON.parse(m.data);
$nickname.textContent = data.nickname;
$message.textContent = data.message;
console.log(m.data);
$li.append($nickname);
$li.append($message);
$msgListUl.append($li);
});
html 요소를 추가하는 부분은 일단 무시하고,
const data = JSON.parse(m.data);
$nickname.textContent = data.nickname;
$message.textContent = data.message;
서버에서 클라이언트측으로 보내면, 클라이언트 측에서 서버로 보내면 버퍼데이터로 내가보낸 문자열 그대로 날려지는 것과 달리 서버에서 클라이언트는 객체로 온다.
그 message객체안의 data라는 객체안에 서버로부터 날라온 데이터가 들어있다.(문자열 형태로)
그거를 우선 JSON.parse()해서 json형태의 문자열이었던 것을 객체로 바꿔버린다.
그 다음 그 데이터를 쓰면 된다.
나는 그냥 send를 누르면 nickname, message가 있는 객체로 만들어서 보냈는데,
만약 서버에서 메시지별로 다르게 처리하도록 하고 싶다면,
{
type:"nickname",
payload : "명수"
}
이런 식으로 클라이언트에서 만들어서 서버에 보내고,
서버에서는
swtich(data.type){
case "nickname":
break;
case "message" :
break;
}
이런 식으로도 할 수 있을 것 같다.
참고로, 객체 그대로 전송하는 것은 안 좋다.
내가 javascript로 서버를 만들었다면, 서버에 접속하는 언어가 여러 언어일 수도 있기 때문.
Json이 가장 무난하다.
그러니까 서버에서 클라이언트 쪽으로 데이터를 보내든,
클라이언트 쪽에서 서버로 데이터를 보내든,
Json이라는 택배상자로 잘 포장해서 보내야 한다.
그리고, socket은 기본적으로 객체이기 때문에,
우리가 원하는 값을 저장시켜 놓을 수 있다.
뭐 예를 들어 socket.nickname = "명수";
라던지.
즉, 소켓끼리 구분이 가능하다는 말.
connection 이벤트때는 연결, 즉 초기화 작업을 해준다 그런 느낌이고,
거기에 이벤트 추가하는 건 이벤트에 따라 어떻게 할 것인지.
내가 이거를 close 할 때 sockets에 있던 걸 제거하려고 했는데,
close로 오는 socket은 좀 다른건가 봄.
뭔가 socket.ip라든지 해서 다른 기준이 있어야 하는건가?
여튼 근데 내가 보낸 message는 굳이 내게는 또 다시 보낼 필요 없으니
function doProcessByMessage(m, socket){
const msgObj = msgToObject(m);
switch(msgObj.type){
case "message":
const sendNick = socket.nickname;
const dataForsend = {
type:"message",
payload:`${sendNick} : ${msgObj.payload}`
}
const scIdx = sockets.indexOf(socket);
console.log(scIdx);
for(let i = 0; i < scIdx; i++){
sockets[i].send(JSON.stringify(dataForsend));
}
for(let i = scIdx+1; i < sockets.length; i++){
sockets[i].send(JSON.stringify(dataForsend));
}
break;
}
이렇게 자기 socket 인덱스 찾아서 그거 빼고 보내도록 함.
scIdx전까지 보내고,
scIdx + 1 부터 다시 전송하고.
또 close 할 때도,
socket.on("close", ()=>{
const idx = sockets.indexOf(socket);
console.log(sockets.length);
console.log(socket === sockets[idx]);
sockets.splice(idx,1);
for(let i = 0; i < sockets.length; i++){
console.log(i);
}
console.log("Disconnected socket");
});
이렇게 자기 idx 찾아서 제거토록 함.
close 됐는데도 보낼 이유가 없으니까.
프론트엔드 쪽 app.js에서
연결하는 서버를 이렇게 하면 다른 컴퓨터에서도 연결이 된다 (주변에서만) LAN 범위 일려나?
'실시간 > WebSocket을 이용한 채팅' 카테고리의 다른 글
5. 웹소켓으로 다른 브라우저 끼리 메시지 주고받기 (0) | 2023.10.25 |
---|---|
4. 웹소켓으로 클라이언트와 서버 간 메시지 주고받기 (0) | 2023.10.19 |
3. 웹소켓 이벤트 (0) | 2023.10.19 |
2. 웹소켓 서버 구현 (0) | 2023.10.18 |
1. HTTP와 WebSocket (0) | 2023.10.18 |