Сокет-сервер с несколькими клиентами, отправка сообщений многим клиентам без ущерба для живости - PullRequest
0 голосов
/ 19 апреля 2010

У меня небольшой сокет-сервер, и мне нужно распространять различные сообщения от клиента к клиенту в зависимости от различных условий.

Однако я думаю, что у меня есть небольшая проблема с живостью в моем текущем коде, и есть ли что-то не так в моем подходе:

public class CuClient extends Thread
{

Socket socket = null;
ObjectOutputStream out;
ObjectInputStream in;
CuGroup group;

public CuClient(Socket s, CuGroup g)
{
    this.socket = s;
    this.group = g;
    out = new ObjectOutputStream(this.socket.getOutputStream());
    out.flush();
    in = new ObjectInputStream(this.socket.getInputStream());
}

@Override
public void run()
{
    String cmd = "";
    try {
        while (!cmd.equals("client shutdown")) {
            cmd = (String) in.readObject();
            this.group.broadcastToGroup(this, cmd);
        }
        out.close();
        in.close();
        socket.close();
    } catch (Exception e) {
        System.out.println(this.getName());
        e.printStackTrace();
    }
}

public void sendToClient(String msg)
{
    try {
        this.out.writeObject(msg);
        this.out.flush();
    } catch (IOException ex) {
    }
}

И моя CuGroup:

public class CuGroup
{
private Vector<CuClient> clients = new Vector<CuClient>();


public void addClient(CuClient c)
{
    this.clients.add(c);
}

void broadcastToGroup(CuClient clientName, String cmd)
{
    Iterator it = this.clients.iterator();
    while (it.hasNext()) {
        CuClient cu = (CuClient)it.next();
        cu.sendToClient(cmd);
    }
}
}

И мой основной класс:

public class SmallServer
{
public static final Vector<CuClient> clients = new Vector<CuClient>(10);
public static boolean serverRunning = true;
private ServerSocket serverSocket;
private CuGroup group = new CuGroup();

public void body()
{
    try
    {
        this.serverSocket = new ServerSocket(1337, 20);
        System.out.println("Waiting for clients\n");
        do
        {
            Socket s = this.serverSocket.accept();
            CuClient t = new CuClient(s,group);
            System.out.println("SERVER: " + s.getInetAddress() + " is connected!\n");
            t.start();
        } while (this.serverRunning);
    } catch (IOException ex)
    {
        ex.printStackTrace();
    }
}

public static void main(String[] args)
{
    System.out.println("Server");
    SmallServer server = new SmallServer();
    server.body();
}
}

Рассмотрим пример со многими другими группами, возможно, с коллекцией групп. Если они все синхронизируются на одном объекте, я не думаю, что мой сервер будет работать очень быстро.

У меня есть шаблон или что-то, что может помочь моей жизненности?

Ответы [ 2 ]

1 голос
/ 19 апреля 2010

Самым большим недостатком с точки зрения корректности является то, что ObjectOutputStream не является потокобезопасным классом. Вызывая sendToClient из разных потоков, вы подвергаетесь большой гонке, когда два исходящих сообщения смешиваются друг с другом.

Два простых, но неэффективных решения: 1) синхронизировать sendToClient, 2) создать поток отправителя для каждого клиента, который читает из BlockingQueue, и изменить sendToClient для добавления в эту очередь. Первый является расточительным, потому что один клиент с высокой задержкой будет узким местом других. Последнее расточительно, потому что требует двойного количества потоков. Как сказал @spender, асинхронный ввод-вывод действительно был бы лучше для этого кода, но он, конечно, не так прост для кода.

0 голосов
/ 19 апреля 2010

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

Есть несколько ответов на этот вопрос, которые могут указать вам правильное направление:

Асинхронный ввод-вывод в Java?

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