2009-07-20 2 views
2

Я пишу чат-сервер на основе Java, и в настоящее время мой проект основан на следующем: - , когда человек в чате отправляет сообщение, класс чата на стороне сервера, отправляет одно и то же сообщение каждому пользователю участник в комнате в петле. Очевидно, что это плохой дизайн, потому что звонки в сети производятся для отдельных участников цикла. Следовательно, например, подумайте, что в чате есть 10 человек. Когда один пользователь отправляет сообщение, класс chatru отправит одно и то же сообщение в цикле всем 10 людям. если можно сказать, 5-й человек в цикле имеет дрянное соединение, время, когда шестой .. 10-й человек увидит, что сообщение будет затронуто.Java Chat Server

Если я перейду от одноадресной передачи к многоадресной рассылке за номер, то как мне получить частную групповую IP-адрес в чате? Кроме того, кажется, что излишнее количество отдельных групп в чате. Одна из основных проблем заключается в том, что когда я ответил пользователям в комнате через цикл, метод, который отправил данные через соединение сокета, блокировал. Следовательно, я думаю, что если я использую неблокирующие сокеты NIO, а затем отправлю сообщение получателям в цикле, это решит проблему? Есть ли другие умные трюки, которые можно сделать для оптимизации отправки данных получателям в комнате?

+0

Попробуйте разделить это на пункты, чтобы люди могли его прочитать. – cdmckay

ответ

3

Простая реализация заключается в использовании двух потоков для каждого клиента. Один поток для чтения из сокета, другой для записи в сокет. Если у вас мало клиентов, все будет в порядке. Вам нужно будет познакомиться с NIO, чтобы обращаться со многими клиентами. («много» означает, что резьбовая модель не работает хорошо.)

Поток чтения клиента считывает целое сообщение из сокета и помещает его в очередь в объекте ChatRoom. В комнате чата есть поток, который выводит сообщения из очереди и помещает их в очередь клиента. Клиент, записывающий поток, опросает свою очередь и записывает сообщение в сокет.

В ChatRoom есть поток, чтобы принимать соединения и создавать объекты-клиенты и помещать их в коллекцию. Он имеет другой поток для опроса своей очереди сообщений и распространения сообщений на очереди клиентов.

Apache Mina имеет пример использования НИО

+0

С 2 потоками на одного клиента и опросом и спящим потоком, потоки переключения контекста и планирования потоков с помощью виртуальной машины будут линейно расти с количеством клиентов. Я собираюсь развернуть его на товарном оборудовании, таком как двухъядерный процессор, я думаю, что планировщик vm сохранит загрузку процессора в основном с предотвращаемой работой. – 2009-07-20 05:35:19

+0

Единственный номер, который вы упоминаете как клиенты, - 10. По моему опыту у вас не будет проблем с обработкой 10 разговоров с любым оборудованием. – Clint

+1

@ Maninder Batth вы видели http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html – grom

2

Я согласен, что серийно зацикливание над вашим получателям будет плохой идеей. Для этого вы можете использовать ThreadPool для помощи. Тем не менее, я думаю, что Multicast будет вашим лучшим выбором. Он хорошо подходит для модели чата. Вам нужно будет отправить сообщение только один раз, и ваш итеративный подход будет разрешен. Вы можете получить уникальный идентификатор группы, указав другой порт в своем адресе.

+0

Я думаю, что многоадресная передача Java поддерживает только UDP, что означает, что сервер не может сказать, успешна ли доставка сообщений без какого-либо ACK от получателя. –

+0

Я пытаюсь сделать его очень обобщенным продуктом, и возможно, что некоторые клиентские сети могут не поддерживать многоадресную рассылку. Следовательно, я не решаюсь пойти с многоадресным подходом – 2009-07-20 06:02:33

+0

@ Zach Scrivena: Я согласен, компромисс для эффективности Multicast - это потеря целостности данных (упорядочение данных и потенциальная потеря). Однако, для чего-то вроде чата, я вижу это как жизнеспособную торговлю. – akf

2

Простым подходом является использование двух потоков на клиентское соединение. Один поток обрабатывает чтение сообщений от клиента, другой для отправки сообщений, тем самым может одновременно отправлять и получать сообщения от клиента.

Чтобы избежать сетевых вызовов при переходе по клиентским соединениям для передачи сообщения, поток сервера должен добавлять сообщения в очередь для отправки клиенту. LinkedBlockingQueue в java.util.concurrent отлично подходит для этого. Ниже приведен пример:

/** 
* Handles outgoing communication with client 
*/ 
public class ClientConnection extends Thread { 
    private Queue<String> outgoingMessages = new LinkedBlockingQueue<String>(MAX_OUTGOING); 
    // ... 
    public void queueOutgoing(String message) { 
     if (!outgoingMessages.offer(message)) { 
      // Kick slow clients 
      kick(); 
     } 
    } 

    public void run() { 
     // ... 
     while (isConnected) { 
      List<String> messages = new LinkedList<String>(); 
      outgoingMessages.drainTo(messages); 
      for (String message : messages) { 
       send(message); 
      } 
      // ... 
     } 
    } 
} 

public class Server { 
    // ... 
    public void broadcast(String message) { 
     for (ClientConnection client : clients) { 
      client.queueOutgoing(message); 
     } 
    } 
} 
+0

Таким образом, количество потоков на сервере будет примерно равным: - количество людей * 2. Скажем, я хочу обслуживать как минимум 1000 человек на чат-сервер. Кроме того, я хотел бы, по крайней мере, 5 серверов на аппаратный компьютер. Также предположим, что аппаратное обеспечение является двухъядерным сервером. Следовательно, 2000 потоков на сервер и 10 тыс. Потоков на 5 серверов на двухъядерной машине. с 50% нитями, активными в любое время, потоками 5 тыс. на двухъядерный ядро, я вижу, что при переключении контекста и планировании потоков будет слишком много времени. Любые комментарии ? – 2009-07-20 06:28:08

+0

NPTL может обрабатывать множество соединений. См. Http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html. – grom