Чат - это общение один-ко-многим, в то время как каждый из множества может отправлять сообщения и получать сообщения от всех остальных.
Эти два действия (отправка, получение) происходят непрерывно. Так что это выглядит как бесконечный цикл, в то время как пользователь может войти (присоединиться к чату) и выйти (покинуть чат).
- введите
- отправить сообщение
- получить сообщение
- выход
Таким образом, цикл на стороне клиента выглядит следующим образом (псевдокод):
while (userInChat)
{
if (userEnteredMessages)
{
userSendMessages(userEnteredMessages)
}
if (chatNewMessages)
{
displayMessages(chatNewMessages)
}
}
Как вы уже отметили в своем вопросе, проблема заключается в том, чтобы внедрить подобный чат для веб-сайта.
Чтобы реализовать такой «цикл» для веб-сайта, вы в первую очередь сталкиваетесь с ситуацией, когда вы не хотите, чтобы здесь был реальный цикл. Пока пользователь находится в чате, он будет запускаться, запускаться и запускаться. Итак, вы хотите распределить выполнение цикла по времени.
Для этого вы можете преобразовать его в набор функций событий:
ChatClient
{
function onEnter()
{
}
function onUserInput(messages)
{
sendMessages = send(messages)
display(sendMessages)
}
function onReceive(messages)
{
display(messages)
}
function onExit()
{
}
}
Теперь возможно инициировать события вместо цикла. Осталась только реализация, которая запускает эти события с течением времени, но на данный момент это не очень интересно, потому что это будет зависеть от того, как на самом деле реализован обмен данными чата.
Всегда существует удаленная точка, к которой клиент чата (каким-то образом) подключен, чтобы отправлять свои собственные сообщения и получать новые сообщения.
Это своего рода поток сообщений чата. Опять же, это выглядит как петля, но на самом деле это поток. Как и в цикле клиентов чата, в определенный момент он подключается к потоку и отправляет входные данные (запись) и получает выходные данные (чтение) из этого потока.
Это уже видно в приведенном выше псевдокоде ChatClient, происходит событие, когда пользователь вводит одно или несколько сообщений, которые затем будут отправлены (записаны). И прочитанные сообщения будут доступны в функции события onReceive.
Поскольку поток данных в порядке, должен быть порядок. Поскольку все это основано на событиях и доступно несколько клиентов, это требует определенной обработки. Поскольку порядок относительно, он будет работать только в его контексте. Контекстом может быть время (одно сообщение предшествовало другому сообщению), но если у клиента чата есть другие часы в качестве сервера или другого клиента, мы не можем использовать существующие часы в качестве источника времени для порядка сообщений, так как обычно отличается между компьютерами в глобальной сети.
Вместо этого вы сами создаете время для выстраивания всех сообщений. При совместном использовании времени для всех клиентов и серверов можно реализовать упорядоченный поток. Это может быть легко сделано, просто пронумеровав сообщения в центральном месте. К счастью, ваш чат имеет центральное место, сервер.
Поток сообщений начинается с первого сообщения и заканчивается последним. Итак, вы просто даете первому сообщению номер 1, а затем каждое новое сообщение получит следующий более высокий номер. Давайте назовем это идентификатором сообщения.
Таким образом, независимо от того, какую серверную технологию вы будете использовать, чат знает тип сообщений: сообщения с идентификатором и сообщения без идентификатора. Это также представляет статус сообщения: либо не часть, либо часть потока.
Не связанные с потоком сообщения - это сообщения, которые пользователь уже ввел, но которые еще не были отправлены на сервер. Пока сервер получает «свободные» сообщения, он может поместить их в поток, назначив идентификатор:
function onUserInput(messages)
{
sendMessages = send(messages)
display(sendMessages)
}
Как показывает этот пример псевдокода, это то, что здесь происходит. Событие onUserInput получает сообщения get, которые еще не являются частью потока. Подпрограмма sendMessages вернет их потоковое представление, которое затем отобразится.
Затем программа отображения может отображать сообщения в порядке их потоков.
Таким образом, независимо от того, как реализовано взаимодействие клиент / сервер, с такой структурой вы можете фактически обрабатывать систему чата на основе сообщений и отсоединять ее от базовых технологий.
Единственное, что нужно сделать серверу, - это принять сообщения, присвоить каждому сообщению идентификатор и вернуть эти идентификаторы.Назначение идентификатора обычно выполняется, когда сервер сохраняет сообщения в своей базе данных.Хорошая база данных обеспечивает правильную нумерацию сообщений, поэтому делать особо нечего.
Другое взаимодействие - чтение новых сообщений с сервера.Чтобы сделать это по сети эффективно, клиент сообщает серверу, с какого сообщения ему нравится читать.Затем сервер будет передавать сообщения с этого времени (ID) клиенту.
Как видно, из «бесконечного» цикла вначале он теперь превратился в систему на основе событий с удаленными вызовами.Поскольку удаленные вызовы дороги, лучше сделать так, чтобы они могли передавать много данных за одно соединение.Часть этого уже находится в псевдокоде, поскольку возможно отправлять одно или несколько сообщений на сервер и получать ноль или более сообщений от сервера одновременно.
Идеальная реализация состояла бы в том, чтобы иметь одно соединение ссервер, который позволяет читать и писать сообщения в полнодуплексном режиме.Однако в javascript такой технологии еще не существует.Эти вещи разрабатываются с помощью Websockets и API-интерфейсов Webstream и тому подобного, но на данный момент давайте упростим ситуацию и посмотрим, что у нас есть: HTTP-запросы без сохранения состояния, немного PHP на сервере и база данных MySQL.
Поток сообщенийможет быть представлен в таблице базы данных, которая имеет автоматически увеличивающийся уникальный ключ для идентификатора и другие поля для хранения сообщения.
Сценарий записи транзакции просто подключится к базе данных, вставит сообщение (я) ивернуть идентификаторы.Это очень распространенная операция, и она должна быть быстрой (mysql имеет своего рода мост memcache, который должен сделать операцию сохранения еще более быстрой и удобной).
Сценарий чтения транзакций одинаково прост, он просто прочитает всесообщения с идентификатором выше, чем переданные ему и возвращающие его клиенту.
Сохраняйте эти сценарии как можно более простыми и оптимизируйте время чтения / записи в хранилище, чтобы они могли выполняться быстро, и все готоводаже при общении по обычному HTTP.
Тем не менее ваш веб-сервер и общее интернет-соединение могут быть недостаточно быстрыми (хотя существует keep-alive ).
Однако HTTPна данный момент должно быть достаточно, чтобы проверить, действительно ли ваша система чата работает без каких-либо циклов, ни на стороне клиента, ни на стороне сервера.
Также хорошо, чтобы серверы были простыми, потому что каждый клиент полагается на них, поэтомуони должны просто делать свою работу и все.
Вы можете в любой момент сменить сервер (или предложить другой тТипы серверов), которые могут взаимодействовать с вашим клиентом чата, предоставляя клиенту чата различные реализации функций отправки и получения.Например, я вижу в вашем вопросе, что вы используете комету, это также должно работать, вероятно, легко внедрить сервер для кометы.
Если в будущем веб-сокеты станут более доступными (что, возможно, никогда не будетслучай из соображений безопасности), вы также можете предложить другой тип сервера для веб-сокетов.Пока структура данных потока не повреждена, это будет работать с разными типами серверов рядом друг с другом.База данных позаботится о соответствии.
Надеюсь, что это полезно.
В качестве дополнительного примечания: HTML5 предлагает нечто, называемое Потоковые обновления с сервером.Отправленные события с онлайн-демонстрацией и PHP / JS .Функция HTML 5 уже предлагает объект события в javascript, который можно использовать для создания примерной транспортной реализации клиента чата.