Introduction
사실 개발하면서 많이들 배우는 웹소켓인데 난 남들과는 다르게 배워왔고 내가 만들려고 목표했던 서비스는 웹소켓 기능이 필요가 없었다.
근데 이번에 개인 프로젝트를 하면서 기능개발하는데 필요한것 같아서 배우게됨.
쉽다고해야할지 어렵다고 해야할지.. 암튼 배워두면 좋은 내용임.
# 우리가 흔히 아는 api통신
우리가 프론트랑 백을 개발했다고 하고 프론트서버에서 클라이언트가 받은 웹사이트가 렌더링되고 그 클라이언트는 백단으로 각각 기능마다 api요청을 보낸다. 해당 api요청을 받으면 백단 서버는 그에 맞는 응답을 해준다.
1요청 1응답. 이게 바로 우리가 아는 기본적인 api요청 플로우? 원칙? 같은거다.
# 만약 이런기능을 개발해보려고 한다면?
프론트단 백단 전부 구현을 해본사람이라면 알거다. 클라이언트는 서버를 특정해서 api요청을 보낼 수 있다. 아이피정보가 있으니까.
하지만 서버는? '요청을 받아야만' 해당 요청에대한 1:1 응답을 할 수 있는 구조다. 때문에 클라이언트를 특정해서 그 클라이언트한테만 데이터를 보낼수가 없다.
물론 억지로라도? 한다면.. 클라이언트가 api요청을 보내고 서버는 최대한 응답을 느려터지게 한다음에 (예를들어 promise를 pending상태로 둔다거나..) 원하는 대답을 줄 타이밍에 응답한다던지 이런식으로도 할수 있을것같은데 이게 웹소켓 같기도함.
근데 이건 서버가 한번만 응답을 할 수 있다는 점에서 또 안되긴함.
# 그럼 이런방식은 어떨까?
이렇게 클라이언트가 어떤 api요청을 보내면 서버는 이 클라이언트에 대한 커넥션을 하나 만든다.
클라이언트도 제대로 서버가 응답을 헀다면 커넥션을 만든다.
즉 둘다 이 커넥션 정보를 가지고있다는 소리.
그 이후에 필요할때마다 이 커넥션 상으로 데이터를 주고받으면 서버와 클라이언트간의 통신이 api요청처럼 무조껀 1대1대응일 필요도 없고, 서버에서도 이 클라이언트를 특정할 수 있다. 이게 바로 웹소켓임
# 실습해보자! 일단 커넥션 만들기
둘다 nodejs로 돌렸음!
//client_ws.js
const WebSocket = require("ws");
const ws = new WebSocket("ws://localhost:1234");
ws.on("open", () => {});
이 코드는 클라이언트 역할을 할거다.
ws는 기본 내장모듈인듯?
얘는 웹소켓 서버를 로컬호스트 포트 1234번으로 연결하려고 할거임.
//back_ws.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 1234 });
wss.on("connection", (ws) => {
console.log("백단에서 커넥션 하나 생성됐어");
});
이 코드가 백단 서버 코드다.
얘는 포트 1234번에서 웹소켓 서버를 만들겠다는거임.
그리고 그 아래에 커넥션이 생성되면 콘솔로 커넥션 생성됐다고 찍어줌.
참고로 postman으로 해보려고했는데 ws는 지원안한다고하고.. tcp통신이라 될줄알았는데.. api요청은 아닌가보다.
그리고 난 사실 처음에 프론트 서버를 직접 만들어서 코드 테스트했는데 그러면 프론트 코드도 새로 써야하고 돌리고 자시고 머시고 해야해서 실습에선 최대한 간단하게 해보려고 저렇게 둘다 nodejs로 돌렸다.
먼저 저 코드들로 백단서버를 돌린후에 클라이언트 서버를 돌리게 되면
이렇게 커넥션을 만들어준다. 클라이언트 js파일을 계속 실행할때마다 커넥션이 생성된다는 말이 나올거임
백단 돌릴때도 저 코드는 실행되는데 이건 기본적으로 코드가 웹소켓을 만들어주기떄문임..
api요청을 받아야 커넥션 만들어주는걸로 난 했는데 그럼 코드가 복잡해지니 이렇게 해보자.
# 클라이언트에서 메세지 보내기
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
일단 난 데이터를 객체로 보내는걸 좋아하니 저렇게 클래스를 하나 만들어줬다.
저기에 적절한 인수를 넣으면 적절한 객체가 튀어나올거임
- 클라이언트에서
ws.on("open", () => {
//웹소켓 커넥션 생성(서버랑)
//아래 data라는 객체를 웹소켓 서버에 보낼거임!
const data = new ConnectionData(
"muzzi",
"server",
"안녕? 난 무찌야",
"entry"
);
ws.send(JSON.stringify(data)); //요기서 백단에 메세지를 보냄.
});
- 백단서버에서
//back_ws.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 1234 });
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
wss.on("connection", (ws) => {
console.log("벡단에서 커넥션 하나 생성됐어");
//클라이언트로부터 받은 데이터
ws.on("message", (message) => {
const message_from_client = JSON.parse(message);
//여기부터 데이터 처리 로직
console.log("받은 데이터 : ", message_from_client);
console.log(`${message_from_client.from}님이 접속하셨어요!`);
});
});
이 코드들을 실행해보면
프론트 코드를 실행할때마다 백단 콘솔에서 받은데이터와 무찌님이 접속했다고 잘 찍어준다.
백단 코드를 재실행했을떄도 계속 무찌한테 데이터 받았다고 뜨길래 왜그런가 했는데 클라이언트는 자동적으로 웹소켓 커넥션이 끊기면 다시 재시도한다고 하더라. 별 문제 아니었음.
클라이언트 코드를 끄고 백단쪽 재실행하면 저렇게 데이터 안뜸.
# 그럼 백단에서 클라이언트한테 메세지를 줘보자
// client_ws.js
const WebSocket = require("ws");
const ws = new WebSocket("ws://localhost:1234");
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
ws.on("open", () => {
//웹소켓 커넥션 생성(서버랑)
console.log("연결했어!");
//아래 data라는 객체를 웹소켓 서버에 보낼거임!
const data = new ConnectionData(
"muzzi",
"server",
"안녕? 난 무찌야",
"entry"
);
ws.send(JSON.stringify(data)); //요기서 백단에 메세지를 보냄.
});
// 서버로부터 데이터 받을떄
ws.on("message", (message_from_server) => {
console.log("받은 메시지:", message_from_server);
});
클라이언트쪽 코드.
아랫쪽에 ws.on이라고 코드 추가해줌. 서버에서 메세지받을때 실행되는거임.
//back_ws.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 1234 });
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
wss.on("connection", (ws) => {
console.log("벡단에서 커넥션 하나 생성됐어");
//클라이언트로부터 받은 데이터
ws.on("message", (message) => {
const message_from_client = JSON.parse(message);
console.log("받은 데이터 : ", message_from_client);
console.log(`${message_from_client.from}님이 접속하셨어요!`);
// 클라이언트에 메시지 전송
const data = new ConnectionData(
"server",
message_from_client.to,
`${message_from_client.from}님 안녕하세여?`,
"say_hello_from_server"
);
ws.send(JSON.stringify(data)); //여기서 클라이언트한테 메세지를 보냄.
console.log("클라이언트한테 환영하는 답장을 보넀어용~");
});
});
백단쪽 코드.
클라이언트한테 메세지를 보내는 코드를 추가해줬다. ws.send저거임 프론트에서 메세지보내는것과 동일함!
백단이 답장을 아주 잘 준다.
사실 난 이렇게 안쓰려고함.
저기 코드를 보면 커넥션이 연결되고 프론트에서 메세지를 보내면 자동으로 ws.send메서드가 실행되게 되어있어서 저건 단순하게 웹소켓 연결되면 클라이언트한테 답장주는 코드일뿐이다.
그럼 아예 함수를 하나 만들어서 해당 커넥션에서 백단이 일방적으로 메세지 보내게 할수 없을까?
# 웹소켓 객체로 저장해버리기.
백단쪽 코드에서 보면 알겠지만, ws.send메서드가 스코프안에 한정되어있다.
위에서 말한 백단이 원할떄 클라이언트한테 해당 커넥션으로 메세지를 보내기 위해서는 이 객체 자체를 뺴야한다.
//back_ws.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 1234 });
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
let connection = {};
wss.on("connection", (ws) => {
console.log("벡단에서 커넥션 하나 생성됐어");
//클라이언트로부터 받은 데이터
ws.on("message", (message) => {
const message_from_client = JSON.parse(message);
console.log("받은 데이터 : ", message_from_client);
console.log(`${message_from_client.from}님이 접속하셨어요!`);
if (message_from_client.type == "entry") {
//만약 클라이언트 메세지 타입이 entry면 커넥션으로 ws객체를 저장하자.
connection.wsObj = ws;
connection.wsClient = message_from_client.from;
console.log(connection); // 여기서 커넥션이 잘 저장됐는지 보자!
}
// 클라이언트에 메시지 전송
const data = new ConnectionData(
"server",
message_from_client.to,
`${message_from_client.from}님 안녕하세여?`,
"say_hello_from_server"
);
ws.send(JSON.stringify(data)); //여기서 클라이언트한테 메세지를 보냄.
console.log("클라이언트한테 환영하는 답장을 보넀어용~");
});
});
백단쪽에 해당 커넥션 웹소켓을 따로 connection이라는 빈 객체를 전역에 만들어서 저장해줬다. 그리고 클라이언트가 웹소켓 연결하고 첫 인사메세지를 보낼때 해당 ws객체를 커넥션 객체에 wsObj라는 프로퍼티로 저장한다.
그리고 해당 클라이언트 이름 또한 첫 메세지로 받았으니, 이것또한 구분하기위해서 객체에 wsClient라는 프로퍼티로 저장을 한다.
때문에 type을 메세지 클래스에 설정해줬음
저기 저장된 connection객체를 콘솔로 찍어줬음
그리고 백단 코드를 재실행해보면?
저장된 wsObj가 졸라 길어서 짤렸는데 암튼 wsClient는 muzzi가 보냈고 해당 ws객체도 저장이 잘 되었다.
사실 이건 이렇게 ws연결은 보통 어레이나 map에다가 담는다. 왜냐면 여러 클라이언트가 접속하면 여러 커넥션이 필요하고 커넥션을 특정해야 하기떄문. 실습이니까 일단 이렇게 간단하게 해봄.
# 그럼 서버가 임의로 클라이언트한테 해당 커넥션으로 메세지를 보내볼까?
const sendMessageToClient = () => {
const data = new ConnectionData(
"server",
connection.wsClient,
`${connection.wsClient}님 이건 서버에서 원할때 보낸 메세지에요`,
"message_from_server"
);
connection.wsObj.send(JSON.stringify(data));
};
setTimeout(() => {
console.log("클라이언트한테 서버가 아무 메세지나 보냈어영");
sendMessageToClient();
}, 3000);
sendMessageToClient라는 함수를 정의해줬고 저기서 connection에 넣어둔 데이터를 사용했다.
클라이언트는 아까 wsClient로 저장해놨기 때문에 갖다 쓸 수 있고 connection.wsObj라는 표현식으로 해당 커넥션 객체를 갖다 불러와서 .send메서드를 사용할 수 있다. 메세지 보내는거임.
그리고 임의로 보냈다는걸 전제했으니까 setTimeout함수로 3초후에 저 sendMessageToClient함수가 호출되도록 했다.
클라이언트 쪽 콘솔을 보면?
백단이 아무때나 보낸 메세지를 잘 받아왔다.
# 커넥션 끊기
- 먼저 일방적으로 상대방쪽에서 커넥션이 끊어졌을때 실행되는 코드는?
wss.on("connection", (ws) => {
console.log("벡단에서 커넥션 하나 생성됐어");
//클라이언트로부터 받은 데이터
ws.on("message", (message) => {
const message_from_client = JSON.parse(message);
console.log("받은 데이터 : ", message_from_client);
console.log(`${message_from_client.from}님이 접속하셨어요!`);
if (message_from_client.type == "entry") {
//만약 클라이언트 메세지 타입이 entry면 커넥션으로 ws객체를 저장하자.
connection.wsObj = ws;
connection.wsClient = message_from_client.from;
}
// 클라이언트에 메시지 전송
const data = new ConnectionData(
"server",
message_from_client.to,
`${message_from_client.from}님 안녕하세여?`,
"say_hello_from_server"
);
ws.send(JSON.stringify(data)); //여기서 클라이언트한테 메세지를 보냄.
console.log("클라이언트한테 환영하는 답장을 보넀어용~");
});
// // 연결이 종료되었을 때 여기가 실행됨!
ws.on("close", () => {
console.log("클라이언트와의 연결이 끊겼어");
});
});
저기 연결종료시에 실행되는 ws.on('close',~~~이런식으로 된다.
이건 백단 코드인데, 프론트쪽 코드에도
// client_ws.js
const WebSocket = require("ws");
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
const createWs = () => {
const ws = new WebSocket("ws://localhost:1234"); // WebSocket 인스턴스 생성
ws.on("open", () => {
//웹소켓 커넥션 생성(서버랑)
console.log("연결했어!");
//아래 data라는 객체를 웹소켓 서버에 보낼거임!
const data = new ConnectionData(
"muzzi",
"server",
"안녕? 난 무찌야",
"entry"
);
ws.send(JSON.stringify(data)); //요기서 백단에 메세지를 보냄.
});
// 서버로부터 데이터 받을떄
ws.on("message", (message_from_server) => {
console.log("서버로부터 받은 메시지:", message_from_server);
});
// 연결이 종료되었을 때
ws.on("close", () => {
console.log("연결 끊겼어.");
});
};
// 1초 후에 createWs 호출하여 WebSocket 생성
setTimeout(() => {
createWs();
}, 1000);
이렇게 똑같은 커넥션 끊어진걸 확인하는 코드를 추가해주자.
이건 상대방쪽에서 연결을 끊거나, 시스템 문제로 끊겼을때 자동으로 실행이 된다.
++추가해서 왜 createWs라는 함수로 따로 감싸고 setTimeout으로 1초후 연결시도하게 헀냐면, nodemon으로 실행하는데 계속 실행하자마자 계속 서버가 끊김. 백단서버도 nodemon으로 실행하니까 아마 순서차이때문에 백단 ws서버가 늦게생성?되서 그걸 client에서 감지하고 커넥션을 끊어버리는것같음.. 그래서 함수로 감싸고 setTimeout으로 1초후에 연결 생성하게 바꿈.
- 먼저 백단에서 임의로 커넥션을 끊는걸 해보자
//back_ws.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 1234 });
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
let connection = {};
wss.on("connection", (ws) => {
console.log("벡단에서 커넥션 하나 생성됐어");
//클라이언트로부터 받은 데이터
ws.on("message", (message) => {
const message_from_client = JSON.parse(message);
console.log("받은 데이터 : ", message_from_client);
console.log(`${message_from_client.from}님이 접속하셨어요!`);
if (message_from_client.type == "entry") {
//만약 클라이언트 메세지 타입이 entry면 커넥션으로 ws객체를 저장하자.
connection.wsObj = ws;
connection.wsClient = message_from_client.from;
console.log("ws객체 저장했어!");
}
// 클라이언트에 메시지 전송
const data = new ConnectionData(
"server",
message_from_client.to,
`${message_from_client.from}님 안녕하세여?`,
"say_hello_from_server"
);
ws.send(JSON.stringify(data)); //여기서 클라이언트한테 메세지를 보냄.
console.log("클라이언트한테 환영하는 답장을 보넀어용~");
});
// 연결이 종료되었을 때 실행
ws.on("close", () => {
console.log("클라이언트와의 연결이 끊겼어");
});
});
const boomConnection = () => {
if (connection.wsObj) {
connection.wsObj.close(1000, "서버에서 연결을 종료했습니다."); // 1000은 정상 종료 코드
console.log(`${connection.wsClient}와의 연결을 강제로 끊었습니다.`);
connection = {}; // 연결 객체 초기화
} else {
console.log("연결된 클라이언트가 없습니다.");
}
};
setTimeout(() => {
boomConnection();
}, 3000);
아랫쪽에 boomConnection이라는 함수를 만들어줬고 저기에 커넥션 연결됐을떄 전역으로 빼준 connection객체를 가지고 동작한다.
wsObj에서 .close메서드를 사용하면되는데 저 1000번 코드는 뭔지모르겠고.. 커넥션 끊고 아까 저장해둔 커넥션객체도 정보를 다 없애주게했다.
그리고 이 boomConnection 함수를 setTimeout으로 3초후에 호출되게해서 커넥션을 끊어보면
백단쪽에서 연결이 끊긴걸 확인할 수 있음.
ws.on("close", () => {
console.log("클라이언트와의 연결이 끊겼어");
});
이렇게 이벤트핸들러로 연결끊긴걸 감지하고 콘솔찍어주는것도 실행됐고
console.log(`${connection.wsClient}와의 연결을 강제로 끊었습니다.`);
boom함수에서 끊은것도 확인했다.
그리고 클라이언트쪽 콘솔도 확인하면
얘도 동일한 ws.on메서드로 해당연결이 자동으로 끊긴걸 감지한다.
# 클라이언트쪽에서 연결을 끊어볼까?
// client_ws.js
const WebSocket = require("ws");
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
let connection = null;
const createWs = () => {
const ws = new WebSocket("ws://localhost:1234"); // WebSocket 인스턴스 생성
connection = ws;
ws.on("open", () => {
//웹소켓 커넥션 생성(서버랑)
console.log("연결했어!");
//아래 data라는 객체를 웹소켓 서버에 보낼거임!
const data = new ConnectionData(
"muzzi",
"server",
"안녕? 난 무찌야",
"entry"
);
ws.send(JSON.stringify(data)); //요기서 백단에 메세지를 보냄.
});
// 서버로부터 데이터 받을떄
ws.on("message", (message_from_server) => {
console.log("서버로부터 받은 메시지:", message_from_server);
});
// 연결이 종료되었을 때
ws.on("close", () => {
console.log("연결 끊겼어.");
});
};
// 1초 후에 createWs 호출하여 WebSocket 생성
setTimeout(() => {
createWs();
}, 1000);
setTimeout(() => {
connection.close(1000, "연결종료");
console.log("클라이언트에서 연결 끊었어");
}, 2000);
클라이언트쪽에 connection이라는 식별자에 그냥 ws객체 통째로 할당함 귀찮아서ㅋㅋㅋ
그리고 1초후에 커넥션 생기니 2초후에 자동으로 연결끊게 .close메서드를 사용했다.
백단코드는 boom머시기 함수만 걍 주석처리함.
//back_ws.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 1234 });
class ConnectionData {
constructor(from, to, message, type) {
this.from = from;
this.to = to;
this.message = message;
this.type = type;
}
}
let connection = {};
wss.on("connection", (ws) => {
console.log("벡단에서 커넥션 하나 생성됐어");
//클라이언트로부터 받은 데이터
ws.on("message", (message) => {
const message_from_client = JSON.parse(message);
console.log("받은 데이터 : ", message_from_client);
console.log(`${message_from_client.from}님이 접속하셨어요!`);
if (message_from_client.type == "entry") {
//만약 클라이언트 메세지 타입이 entry면 커넥션으로 ws객체를 저장하자.
connection.wsObj = ws;
connection.wsClient = message_from_client.from;
console.log("ws객체 저장했어!");
}
// 클라이언트에 메시지 전송
const data = new ConnectionData(
"server",
message_from_client.to,
`${message_from_client.from}님 안녕하세여?`,
"say_hello_from_server"
);
ws.send(JSON.stringify(data)); //여기서 클라이언트한테 메세지를 보냄.
console.log("클라이언트한테 환영하는 답장을 보넀어용~");
});
// 연결이 종료되었을 때 실행
ws.on("close", () => {
console.log("클라이언트와의 연결이 끊겼어");
});
});
출력결과를 보면?
먼저 클라이언트쪽 출력인데
연결끊겼어는 ws.on('close')이벤트핸들러쪽에서 출력된거고
클라이언트에서 연결끊겼어는
아랫쪽 2초후 실행되는 .close메서드로 실행해서 생긴 결과임
백단쪽 ws.on('close') 이벤트 핸들러에서 끊긴걸 감지하고 알아서 출력해줌.
# 내가 만들어본거
이 포스팅에서 쓴건 nodejs만으로 클라이언트와 서버를 구현했는데 실제로는 브라우저로 클라이언트를 구현하는게 맞다.
일대일 채팅방 기능을 만들어봤는데
무찌도리세팅버튼은 내 아이디랑, 상대방 아이디를 prompt로 저장하는건데 실험하는데 계속하기 귀찮아서 아예 버튼으로 저장되게함
이걸가지고 백단에 요청보내면 무찌 도리 각각 둘다 웹소켓을 생성해준다. 난 포스팅에서 connection으로 했던거임.
그리고 메세지가 서로 오고가면 각각 상대방의 웹소켓에서 .send로 메세지 보내주는거임
핸드폰가지고 석구랑 똥개도 만들어서 테스트해봤는데 일대일채팅방이 잘 개설되더라
아래는 전체코드
실습으로 이렇게했으면 머리아프겠지
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 1234 });
const clients = new Map(); // 사용자 아이디를 키로 WebSocket을 저장
const userPair = new Map(); // 사용자의 연결된 상대방을 저장
class Message {
constructor(from, to, message) {
this.from = from;
this.to = to;
this.message = message;
}
}
console.log(new Message("바보", "엉덩이", "똥개"));
wss.on("connection", (ws, request) => {
let from = null; // 연결된 클라이언트의 아이디
let to = null; // 상대방 아이디를 저장할 변수
ws.on("message", (data) => {
const parsedData = JSON.parse(data);
console.log(parsedData); // { from: null, to: null, message: '하잉' }
// 클라이언트 아이디가 없으면, 새 아이디 등록
if (!from) {
from = parsedData.from;
clients.set(from, ws); // 아이디와 연결된 WebSocket을 저장
console.log(`${from}님이 채팅방에 들어왔습니다.`);
// 상대방에게 "유저가 들어왔습니다" 메시지를 보냄
if (parsedData.to && clients.has(parsedData.to)) {
const targetWs = clients.get(parsedData.to);
targetWs.send(
JSON.stringify({
from: "server",
to: from,
message: `${from}님이 채팅방에 들어왔습니다.`,
})
);
}
}
// 상대방 아이디 설정
to = parsedData.to;
userPair.set(from, to); // 상대방 저장
// 메시지 처리
const { message } = parsedData;
console.log(`${from} -> ${to}: ${message}`);
// 상대방에게 메시지 전달
if (clients.has(to)) {
const targetWs = clients.get(to);
targetWs.send(
JSON.stringify({
from: from,
message: message,
})
);
} else {
console.log(`${to}는 현재 온라인이 아닙니다.`);
}
});
ws.on("close", () => {
if (from) {
// 연결 종료 시 상대방에게 나갔다는 메시지 전송
if (userPair.has(from)) {
const target = userPair.get(from); // 상대방 아이디 가져오기
if (clients.has(target)) {
const targetWs = clients.get(target);
targetWs.send(
JSON.stringify({
from: "server",
message: `${from}님이 대화방을 나갔어요`,
})
);
}
}
clients.delete(from); // 연결 종료 시 WebSocket 삭제
userPair.delete(from); // 상대방 정보 삭제
console.log(`${from}님이 채팅방을 나갔습니다.`);
}
});
});
<template>
<div class="container">
<router-view></router-view>
<div class="container">
<div class="btns">
<button type="button" class="btn btn-primary" v-on:click="test()">
axios
</button>
<button type="button" class="btn btn-primary" v-on:click="chooseMyId()">
무찌 세팅
</button>
<button
type="button"
class="btn btn-primary"
v-on:click="chooseUserId()"
>
도리 세팅
</button>
<button type="button" class="btn btn-primary" v-on:click="openChat()">
open Chatroom
</button>
</div>
<div class="userInfo">
{{ state.user ? state.user : "로그인하세여" }}
</div>
<div class="chatRoom" v-if="state.isChat">
<div
class="message"
v-for="(message, index) in state.chatData"
:key="index"
>
<p>{{ message }}</p>
</div>
<div class="type">
<input type="text" v-model="state.myMessage" />
<button class="btn btn-primary" v-on:click="sendMessage()">
send
</button>
</div>
<button class="btn btn-danger" v-on:click="closeChat()">out</button>
</div>
</div>
</div>
</template>
<script>
import { reactive } from "vue";
import axios from "axios";
axios;
export default {
setup() {
///여기가 데이터
const state = reactive({
user: null,
toUser: null,
chatData: [],
isChat: false,
ws: null,
myMessage: null,
});
const test = () => {
axios.get("/api/test").then((res) => {
alert(res.data);
});
};
///여기가 데이터
///여기가 메서드
const chooseMyId = () => {
// const user = prompt("쓸 아이디 정해줘", "");
state.user = "무찌";
state.toUser = "도리";
};
const chooseUserId = () => {
// const toUser = prompt("누구랑 채팅할래?", "");
state.user = "도리";
state.toUser = "무찌";
};
const openWsServer = () => {
// 상대방 아이디가 없는 경우 채팅방을 열 수 없도록 처리
if (!state.toUser) {
alert("상대방 아이디를 먼저 선택해주세요.");
return;
}
state.isChat = true;
if (state.ws && state.ws.readyState === WebSocket.OPEN) {
console.log("이미 연결된 WebSocket이 있습니다.");
return;
}
// WebSocket 연결
state.ws = new WebSocket("ws://localhost:1234");
state.ws.onopen = () => {
console.log("서버에 연결되었습니다.");
// 서버에 연결되면, 상대방에게 '유저가 들어왔습니다' 메시지를 전송하도록 서버에 알림
state.ws.send(
JSON.stringify({
from: state.user,
to: state.toUser, // 상대방 ID로 설정
message: "하잉", // 이 메시지는 서버가 다른 유저에게 보냄
})
);
};
state.ws.onmessage = (event) => {
const resObj = JSON.parse(event.data);
console.log(resObj);
console.log(resObj.message);
state.chatData.push(resObj); // 메시지를 화면에 출력
};
state.ws.onclose = () => {
console.log("서버와의 연결이 종료되었습니다.");
};
};
const closeChat = () => {
state.isChat = false;
if (state.ws) {
state.ws.close(); // 연결 종료
} else {
console.log("WebSocket이 연결되어 있지 않습니다.");
}
};
const openChat = () => {
state.isChat = true;
openWsServer();
};
const sendMessage = () => {
state.chatData.push({
from: state.user,
to: state.toUser,
message: state.myMessage,
});
state.ws.send(
JSON.stringify({
from: state.user,
to: state.toUser,
message: state.myMessage,
})
);
state.myMessage = null;
};
return {
state,
chooseMyId,
chooseUserId,
openWsServer,
openChat,
closeChat,
test,
sendMessage,
};
},
// 여기에 컴포넌트
};
</script>
<style lang="scss" scoped>
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.btn {
margin: 10px;
}
.userInfo {
background-color: beige;
width: 100%;
display: flex;
justify-content: center;
}
.chatRoom {
width: 100%;
}
}
.sassTest {
p {
color: blue;
}
}
</style>
'javaScript > nodeJs' 카테고리의 다른 글
require.context / 파일경로 가져오기. (0) | 2023.03.08 |
---|---|
production// 배포모드 (0) | 2023.01.16 |
배포시 모듈정리/ (0) | 2022.12.07 |
nodejs // dotenv 사용 (0) | 2022.09.24 |
다른파일로 관리 require//nodejs(js import아님) (0) | 2022.08.06 |