Сетевая связь TCP [Дизайн кода] - PullRequest
4 голосов
/ 27 февраля 2012

В последние несколько дней я много путаюсь с TCP / IP Communication (Используя Java и C #). Я понимаю, как это работает, и могу использовать это. Мой вопрос - это скорее вопрос разработки кода, как сделать лучший и простой способ создать реальное общение.

Например, я построил свой собственный многопользовательский чат-сервер. Я хочу, чтобы мое сообщение могло принимать решение, будь то запрос на аутентификацию или новое сообщение в чате, возможность получения текущего списка пользователей и т. Д. И т. Д.

Я реализовал несколько способов самостоятельно, но я не совсем доволен этим, так как я думаю, что есть более стандартный и красивый способ сделать это.

Моей первой мыслью была строка с разделителями, которая разбита, вот пример моей реализации моего общения в Java:

//The Object-types im Using
clientSocket = new Socket(host, port_number);
_toServer = new PrintStream(clientSocket.getOutputStream());
_fromServer = new DataInputStream(clientSocket.getInputStream());

//Example Commands my Client sends to the server

_toServer.println("STATUS|"); //Gets the Status if server is online or closed (closed can occur when server runs but chat is disabled)
_toServer.println("AUTH|user|pw"); //Sends an auth Request to Server with username and Password
_toServer.println("MESSAGE|Hello World|ALL"); //Sends hello World in the Normal Chat to all Users
_toServer.println("MESSAGE|Hello World|PRIVATE|foo"); //Sends hello World only to the user "foo"
_toServer.println("USERS|GET"); //Request a list of all Connected Users


//Example In the Recieved Message Method where all The Server Messages Get Analyzed
serverMessage = _fromServer.readLine(); //Reads the Server Messages

String action = serverMessage.split("|")[0];

if (action.equals("USERS")) { //Example "USERS|2|foo;bar"
    String users[] = serverMessage.split("|")[2].split(";");
}
if (action.equals("MESSAGE")) { //Example "MESSAGE|Hello World|PRIVATE|foo"
    if(serverMessage.split("|")[2].equals("ALL") {
        //Code and else for private....
    }
}
if (serverMessage.equals("STATUS|ONLINE")) {
    // Code
    // I leave out //Code and } for the next If statements
}
if (serverMessage.equals("STATUS|OFFLINE")) {
if (serverMessage.equals("AUTH|ACCEPTED")) {
if (serverMessage.equals("AUTH|REJECT")) {

Это нормально? Готово? Объявление, которое вы видите, мне нужно отправить коды состояния и объекты, соответствующие коду. Я думал о записи данных в байтах, а также о реализации «декодера для каждого объекта», пример:

int action = _fromServer.readInt();     

//opcodes is just an Enum Holding the corresponding int

switch(action) {
  case(opcodes.MESSAGE):
    break;
  case(opcodes.AUTH):
    break;         
 }

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

Есть ли лучший способ сделать это или даже API / Framework?

Заранее спасибо!

Ответы [ 4 ]

2 голосов
/ 27 февраля 2012

Если ваш проект расширяется, вы можете взглянуть на Netty - это фреймворк для работы с кодом связи. Если ваш код прост, вам будет лучше делать все вручную.

Что касается дизайна протокола, то это зависит от того, что для вас наиболее важно: производительность, расширяемость, удобочитаемость, простота отладки и т. Д. Эти критерии могут в некоторой степени противоречить друг другу, например, высокая производительность может означать предпочтение двоичного файла протоколы, но они негативно влияют на простоту отладки и иногда расширяемость. Обычно хорошей идеей не изобретать велосипед. Получите вдохновение от существующих протоколов. Если вы решили использовать двоичный код, не начинайте с нуля, если только вам это не нужно, начните с Protocol Buffers . Если ваше приложение простое и не нацелено на очень высокую производительность, используйте удобочитаемый протокол, который сделает вашу жизнь проще (отладка и тестирование возможны с помощью стандартных инструментов оболочки, таких как strace и nc).

2 голосов
/ 27 февраля 2012

Если вы разрабатываете протокол для межязыкового общения, я бы предложил не использовать форматированные строки в качестве средства связи, а байты состояния.Например, если вы рассмотрите структуру самого TCP / IP, сообщения состоят из заголовка фиксированного формата и переменной полезной нагрузки.Таким образом, вы всегда знаете, что (например) третий байт сообщения содержит тип сообщения, пятый - состояние ошибки и так далее.Это облегчает обработку.

Если вы спроектировали свой протокол, вы можете рассмотреть возможность работы с явными объектами MessageObject на стороне java, и в этом случае вы бы реализовали фабрику с методами маршаллинга и демаршаллинга для этих объектов, конвертируя объектыот и до сообщений в вашем протоколе.

Если вы полностью Java, вы можете даже сэкономить эти усилия и использовать ObjectInputStreams и ObjectOutputStreams на клиенте и сервере.Если нет, возможно, вы захотите взглянуть на буфер протокола Google: http://code.google.com/intl/de-DE/apis/protocolbuffers/,, который, по сути, делает то же самое для межязыкового общения.

2 голосов
/ 27 февраля 2012

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

Что касается расширения чего-то подобного для консольной игры, я бы начал с внедрения IRC и его использования для изучения написания реальных коммуникационных протоколов. Как только вы это сделаете, вы можете использовать его для добавления своих собственных команд в ваш фреймворк.

1 голос
/ 27 февраля 2012

Я думаю, что Apache MINA поможет вам. http://mina.apache.org/

Создание приложения Java C / S действительно сложно, вам нужно заниматься TCP, UDP и многопоточным программированием; MINA может помочь вам в этих вещах.

Я думаю, что другая часть, в которой вы нуждаетесь, это ваш личный протокол чата, но как насчет сервиса IM с открытым исходным кодом, такого как Jabber? :)

...