#node.js #socket.io #chat #mern
Вопрос:
Согласно документации, чат один на один происходит, когда мы отправляем сообщение конкретному socket.id. например
io.to(socket.id).emit("event","message")
Это будет работать только в том случае, если одновременно подключены два пользователя.
Если мы хотим добавить функцию чата в наше приложение, где зарегистрированные пользователи могут общаться друг с другом (1-1).Каково оптимальное решение для этого?Я реализовал чат с помощью io.to(socket.id),но когда один из пользователей находится в автономном сокете.идентификатор недоступен.
————————————Клиент——————————-
function Chat() {
const [conversations, setConversations] = useState([]);
const [currentChat, setCurrentChat] = useState(null);
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState("");
const [arrivalMessage, setArrivalMessage] = useState(null);
const scrollRef = useRef();
const socket = useRef();
const client = isAuthenticated()
const clientId = isAuthenticated().client._id;
const token = isAuthenticated().client.token
console.log(clientId)
useEffect(() => {
socket.current = io("ws://localhost:8900");
socket.current.on("getMessage", (data) => {
setArrivalMessage({
sender: data.senderId,
text: data.text,
createdAt: Date.now(),
});
});
}, []);
useEffect(() => {
arrivalMessage amp;amp;
currentChat?.members.includes(arrivalMessage.sender) amp;amp;
setMessages((prev) => [...prev, arrivalMessage]);
}, [arrivalMessage, currentChat]);
useEffect(() => {
socket.current.emit("addUser",clientId );
}, [client]);
useEffect(() => {
getconversation(clientId,token).then((data)=>{
if(data.error){
console.log(data.error)
}else{
console.log(data)
setConversations(data)
}
})
}, [])
useEffect(() => {
const getMessages = async () => {
try {
const res = await axios.get("http://localhost:8080/api/messages/" currentChat?._id);
setMessages(res.data);
} catch (err) {
console.log(err);
}
};
getMessages();
}, [currentChat]);
useEffect(() => {
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
const handleSubmit = async (e) => {
e.preventDefault();
const message = {
sender:clientId,
text: newMessage,
conversationId: currentChat._id,
};
const receiverId = currentChat.members.find(
(member) => member !== clientId
);
socket.current.emit("sendMessage", {
senderId: clientId,
receiverId,
text: newMessage,
});
try {
const res = await axios.post("http://localhost:8080/api/messages", message);
setMessages([...messages, res.data]);
setNewMessage("");
} catch (err) {
console.log(err);
}
};
————————-Сервер——————————————
const io = require("socket.io")(8900, {
cors: {
origin: "http://localhost:3000",
},
});
let users = [];
const addUser = (userId, socketId) => {
!users.some((user) => user.userId === userId) amp;amp;
users.push({ userId, socketId });
};
const removeUser = (socketId) => {
users = users.filter((user) => user.socketId !== socketId);
};
const getUser = (userId) => {
return users.find((user) => user.userId === userId);
};
io.on("connection", (socket) => {
//when connect
console.log("a user connected." socket.id);
//take userId and socketId from user
socket.on("addUser", (userId) => {
addUser(userId, socket.id);
io.emit("getUsers", users);
});
//send and get message
socket.on("sendMessage", ({ senderId, receiverId, text }) => {
console.log("receiverid=====>>>",receiverId)
console.log("users ",users)
const user = getUser(receiverId);
console.log("userSocket Id",user)
io.to(user.socketId).emit("getMessage", {
senderId,
text,
});
});
//when disconnect
socket.on("disconnect", () => {
console.log("a user disconnected!");
removeUser(socket.id);
io.emit("getUsers", users);
});
});
Ответ №1:
Сначала необходимо сохранить сообщения в вашем приложении вместе с информацией об отправителе, получателе и отметке времени. Затем используйте веб-сокеты / сокет.ввод-вывод для дополнения функциональности и информирования каждого пользователя в режиме реального времени, если он находится в сети. Этому подходу следуют другие приложения для чата, например Slack.
Таким образом, основными свойствами вашего приложения должны быть,
- Когда пользователь отправляет сообщение, клиент должен отправить его на серверную часть/сервер для хранения.
- Сервер должен выдавать через сокеты сообщение. Это станет более сложным с помощью дополнительных сервисов и т. Д., Как только вы станете больше и у вас появятся кластеры.
- Пользователи, находящиеся в сети, получат сообщение и будут отображаться на экране чата.
- Если пользователи обновятся или пользователь отключен и вернется, все сообщения для этого пользователя будут извлечены с сервера.
Что касается излучающей части, используйте уникальные идентификаторы, например уникальный идентификатор (uuid) сеанса, сгенерированного между одним или несколькими пользователями, для таргетинга на комнату (пользователи должны прослушивать этот идентификатор) или идентификаторы пользователей и излучайте каждому идентификатору пользователя (пользователь может прослушивать свой собственный идентификатор пользователя, как только он будет в Сети). Деталей сообщения должно быть достаточно, чтобы приложение могло отобразить его на нужном экране.
Комментарии:
1. Я сохранил сообщения в своей базе данных с идентификатором отправителя и получателя. Приложение отлично работает, когда пользователь A и пользователь B подключены одновременно. Когда один из них не подключен, мой сервер сокетов не может найти сокет. идентификатор получателя, и он выходит из строя..
2. @ShehryarTanoli вы можете поддерживать подключенных пользователей (или сеансы комнат/групп, если хотите) при подключении к сокету и отключении (вкл. («подключение») и вкл. («отключение»)) в вашей собственной структуре данных в памяти сервера, нет необходимости сохранять ее. Затем повторите и вызовите того, кого вы все еще найдете подключенным.
3. @ShehryarTanoli вы пробовали использовать сокет.»испускать»? Я не вижу ошибки, когда socket.emit («к чему-то случайному»,…
4. Позвольте мне отредактировать вопрос, я поделюсь своим кодом, чтобы вы могли взглянуть на него.
5. вопрос был обновлен