Метод принятия ServerSocket - как я могу привести к типу подкласса?

У меня есть класс ClientSocket, который расширяет класс Socket. Причина, по которой я расширяю класс Socket, заключается в том, что я хочу включить String clientId, который однозначно идентифицирует клиента на другой стороне сокета. У меня также есть метод getClientId, который возвращает clientId.

У меня есть экземпляр ServerSocket, работающий на моем сервере, который принимает соединения сокетов следующим образом:

public Socket acceptNextConnection() throws IOException {
    Socket socket = serverSocket.accept();

    // put the client socket into the map
    ClientSocket clientSocket = (ClientSocket) socket;
    clientConnections.put(clientSocket.getClientId(), clientSocket);

    return clientSocket;
}

Как видите, мое приведение здесь неверно, поскольку экземпляр Socket НЕ ЯВЛЯЕТСЯ экземпляром ClientSocket, и поэтому я получаю исключение приведения класса, как я и ожидал. Как видно из кода, я хочу вызвать getClientId для класса ClientSocket. Однако я не могу этого сделать, потому что метод serverSocket.accept возвращает объект Socket во время выполнения, а не ClientSocket. Мой вопрос в том, есть ли способ обойти это? Если нет, есть ли более аккуратный способ сделать то, что я хочу, который позволяет однозначно идентифицировать сокет, привязанный к клиенту? IP-адрес может быть изменен.

Спасибо за помощь.


person Joeblackdev    schedule 08.03.2011    source источник


Ответы (1)


У вас может быть ServerClientSocket, который возвращает ClientSocket из accept. Что-то типа

public class ServerClientSocket extends ServerSocket {
  public ClientSocket accept() throws IOException {
  if (isClosed())
    throw new SocketException("Socket is closed");
  if (!isBound())
    throw new SocketException("Socket is not bound yet");
  ClientSocket s = new ClientSocket((SocketImpl) null);
  implAccept(s);
  return s;
  }
}
person Peter Lawrey    schedule 08.03.2011
comment
Привет Питер. Спасибо за ответ. Я думал об этом. Это безопасный вариант? Я знаю, что «принять» может генерировать некоторые исключения, но охватываю ли я здесь все возможности, используя описанный выше подход? Кроме того, я не уверен, что понимаю часть создания экземпляра ClientSocket. Можете ли вы объяснить приведение (SocketImpl), а также метод implAccept? Спасибо большое - person Joeblackdev; 08.03.2011
comment
Извините, я только что нашел «implAccept()», имеет смысл. Спасибо! - person Joeblackdev; 08.03.2011
comment
Я взял копию метода accept() и внес минимум изменений. В идеале вы можете отказаться от этого параметра, так как ваш конструктор не обязательно должен быть таким же, как у Socket. - person Peter Lawrey; 08.03.2011
comment
Спасибо за это. Однако я прочитал метод implAccept в ServerSocket и понял, что экземпляр ClientSocket будет передан этому экземпляру ServerClientSocket. Однако я не уверен в ((SocketImpl) null) части приведенного выше кода. Вы можете объяснить? Спасибо еще раз - person Joeblackdev; 08.03.2011
comment
Он просто вызывает конструктор, который принимает (SocketImpl) с нулевым аргументом. Если у вас нет такого конструктора, я предлагаю вам использовать конструктор, который вызывает super((SocketImpl) null);, чтобы его поведение было таким же. - person Peter Lawrey; 08.03.2011
comment
Так должен ли я добавить этот конструктор в мой класс ClientSocket? например, public ClientSocket(SocketImpl si) { super(si); } Спасибо - person Joeblackdev; 08.03.2011
comment
Это может быть самым простым. Не глядя на ваш код, я не могу сказать наверняка. Возможно, вы можете сделать его защищенным или пакетно-приватным. Я бы посмотрел код для Socket, чтобы дать вам некоторые идеи. - person Peter Lawrey; 08.03.2011
comment
Хорошо понял. Я просто настроил конструктор без аргументов в своем классе ClientSocket, который вызывает 'super();'. Еще раз спасибо всем за помощь. - person Joeblackdev; 08.03.2011