Показать сообщение отдельно
Старый 29.10.2015, 09:36   #27
St_AnGer
Элита
 
Аватар для St_AnGer
 
Регистрация: 21.01.2010
Адрес: Россия, Рязанская область, г.Михайлов
Сообщений: 2,067
Написано 1,185 полезных сообщений
(для 2,828 пользователей)
Ответ: Чат: PHP + MySQLi или что то другое?

Спасибо тебе Максим огромное! Ежели бы не ты, сидел бы мой сервачок на пэхапэ и дальше
В общем то, всю "ненужную" часть чатилки я реализовал (ну там добавление в друзья, группы, перенос в группы, удаление, просмотр информации, голосование за принятие в сеть и т.п.). Теперь нужно организовывать сами комнаты и переписку в них. Собственно, пока что я для реализации "онлайн"-переписки остановился на библиотеке socket.io, понравилась она мне своей простотой и мощью.

Для начала, потренироваться в обращении с библиотекой, я решил сделать некое подобие онлайн-оффлайн для пользователей как это было в Аське. Т.е. вошёл - тебе присвоился и отправился всем кому надо статус "онлайн", вышел - соответственно "оффлайн". И вот у меня возник вопрос - а как отправлять данные на нужные сокеты (т.е. только тем у кого ты в друзьях)?

Я сейчас реализовал это ровно так, как вижу сам.

Для начала, моё "api" разделилось на 2 части - часть основанная на чистой node.js (всякая мишура для обвязки чата) и часть использующая socket.io (онлайн-офлайн, комнаты и переписка).

Далее, я каждому пользователю добавил "скрытое" поле in_friend, которое содержит всех кто добавил его в друзья. Сделал я это исключительно из соображений скорости - пробежаться по одному массиву/объекту явно быстрее, чем перебрать всю базу и посмотреть у кого же наш вошедший пользователь в друзьях. Собственно, тут всё просто. А вот дальше началась жесть.

Для того что бы запоминать сокеты для клиентов я создал массив sockets, в который вносятся новые сокеты или обновляются старые при обращении через socket.io. Т.е. массив не содержит данных больше, чем должен содержать. Сравнение "старый-новый" происходит по моему собственному полю _id, которое я внёс в объект session у сокетов. Если сокет с сессией содержащей _id уже есть - заменяем на новый, на данном этапе это не критично, потом, конечно, может не кисло так аукнуться (в конце расписал почему), но будем разбираться с проблемами по мере их поступления, сейчас не об этом.

Так вот, собственно в сокетах реализовал два события, online и offline, которые берут из базы инфу о пользователе (id пользователя передаётся вместе с событием online/offline), достают из поля in_friend все id тех у кого пользователь состои в друзьях, потом я пробегаюсь по массиву с друзьями и внутри по массиву с сокетами, найдя нужный сокет отправляю соответствующее событие тем кого найду в этом массиве. Смущает один момент. Пока количество сокетов крайне мало (я вот имею возможность тестить на 5-6 машинах), перебор массива не представляет опасности. А если сокетов в массиве будет тысяча? Не уничтожит ли это мой сервер, если одновременно событие online/offline передадут хотя бы 20 человек, каждый из которых, допустим, состоит в друзьях у 40 человек? Ведь это уже будет фактически 40*1000*20 = 800000 циклов с отправкой данных по сокетам, что просто нереально дофига на такое маленькое событие как передача статуса online/offline. И точно такое же количество циклов будет и на приглашение в комнату, и на отправку сообщения. Т.е. нагрузка будет очень и очень недурственная только из за такого моего подхода к сокетам.

зыЖ Подсчёт количества циклов очень грубый, у меня стоит break в цикле с сокетами после совпадения _id и отправки статуса. Так как у меня сокеты с _id пользователя не повторяются, то этот подход с выходом из цикла вполне применим, как мне кажется. Но этот же подход накладывает очень существенное ограничение - один пользователь будет сидеть только с одного клиента, причём где зашёл последним, там и будет работать всё, старые сокеты будут замещены новым.

зыыЖ Забыл упомянуть, изредка клиентом посылается "alive"-пакет (раз в 60 секунд сейчас сделал), который записывает отославшему пользователю статус online в базе данных и записывает время получения этого пакета. При запросе списка друзей другими пользователями (у кого в списке есть наш пользователь) идёт проверка дат пакетов "alive", если разница между текущей датой и датой "alive" > 60 секунд - пользователю в базе записывается статус offline. Работает Но, опять же, вопрос возможной нагрузки стоИт остро.

зыыыЖ Сейчас пришла в голову идея хранить все живые сокеты пользователя в базе данных, допустим в поле sockets. Это должно избавить от перебора общего огромного массива сокетов, ведь нужные сокеты (а сокет же в данном случае простой JS объект?) мы сможем достать только лишь опираясь на массив in_friends текущего пользователя. Надо будет попробовать так сделать.
__________________
Main PC:
Intel Core i5 4260U 1.44 GHz + LPDDR3 1x4096 1600 MHz + Intel HD Graphics 5000.

Asus Ёжик T101-MT:
Intel Atom N-570 1.66 Ghz + DDR2 2x1024 800 Mhz + Intel GMA 3150 128 Mb DDR2


Скачать Doom 2D: Remake v0.3.8a

Последний раз редактировалось St_AnGer, 29.10.2015 в 12:36.
(Offline)
 
Ответить с цитированием