Java socket framework

от автора

Всем доброго времени суток.
Разрабатываю онлайн 3д игру, была выбрана платформа java. Для 3d был выбран движок jmonkeyengine.
А в качестве серверной части я решил написать простеньки p2p фреймворк, MVC с реализацией представлений на клиенте.

Где может пригодится:

1. Сервер для мобильных сервисов.
2. Любые многопользовательские приложения где нужно p2p.
3. Онлайн игры.
4. Торрент при желании.

Диаграмма:

image
Принцип работы:
1. Клиент посылает на сервер сообещение в котором перечисляются переменные и какую задачу вызвать.
2. Сообщение попадает очередь входящих сообщений.
3. Роутер запускает нужную задачу с этими переменными.
4. В задаче мы отправляем ответ пользователю.

Дополнительные возможности:
1. Настраивать порты клиента и сервера.
2. Модели базы данных.
3. Валидация входящих сообщений.
4. Права пользователей.
5. Модули.
6. Механизм сессий.
7. Команды.
8. Смена протокола tcp/udp.

Инструкции, примеры и документациия.

http://jsockframework.blogspot.ru/

https://github.com/nnpa/jsock/
youtube

Пример отправки и приема сообщений.

Клиент

//client /*  * jsock framework https://github.com/nnpa/jsock open source  * Each line should be prefixed with  *   */  package jsock.tests;  import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.util.Iterator; import java.util.Scanner; import java.util.logging.Level; import java.util.logging.Logger; import conf.JConfig; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException;  /**  *  * @author padaboo I.B Aleksandrov jetananas@yandex.ru  */ public class JClientTCPTest {          public static void main(String[] args) throws UnknownHostException, IOException, ClassNotFoundException, InterruptedException{        JClientTCPTest tcpTest = new JClientTCPTest();        tcpTest.test();                      }          public void test(){         Sender sender     = new Sender();         sender.start();                  Receiver receiver = new Receiver();         receiver.start();     }          class Sender extends Thread{         @Override         public void run(){             try {                 InetAddress host = InetAddress.getLocalHost();                 Socket socket    = null;                                  String message;                                  for(int i=1; i<10;i++){                     message = "{\"task\":\"JTestTask\",\"message\":\"test"+i+"\"}";                     socket = new Socket(host.getHostName(), JConfig.server_port);                                          //InputStream  inStream = socket.getInputStream();                     PrintWriter socketOut;                                          socketOut = new PrintWriter(socket.getOutputStream(), true);                                        socketOut.println(message);                     socket.close();                     System.out.println("Send: "+i);                     Thread.sleep(100);                                      }             } catch ( IOException | InterruptedException ex) {                 Logger.getLogger(JClientTCPTest.class.getName()).log(Level.SEVERE, null, ex);             }         }     }          class Receiver extends Thread{         JSONObject jsonObj;         JSONParser parser;                  @Override         public void run(){             try {                  ServerSocket serverSocket = new ServerSocket(JConfig.client_port);                 String data = "";                                  while(true){                     data = "";                     Socket   socket      = serverSocket.accept();                      InputStream inStream = socket.getInputStream();                      Scanner scanner      = new Scanner(inStream);                                          while(scanner.hasNextLine()){                         data += scanner.nextLine();                     }                     System.out.println(data);                                     }                              } catch (IOException ex) {                 Logger.getLogger(JClientTCPTest.class.getName()).log(Level.SEVERE, null, ex);             }         }     } } 

Сервер

 package tasks;  import jsock.message.JInMessages; import jsock.message.JOutMessages; import jsock.task.JClientTask; import models.Users;  /**  *  * @author padaboo I.B Aleksandrov jetananas@yandex.ru  */ public class JTestTask extends JClientTask{      public JTestTask(JInMessages message) {         super(message);     }          @Override     public String[][] rules(){         String[][] rules = {              {"require","message"}         };         return rules;     }          @Override     public String rights() {         //String rigths = "user,admin";         String rigths = "guest";                  return rigths;     }      @Override     public void action(){         String message   = this.message.json.get("message").toString();         System.out.println(message);                String outString = "{\"message\":\"Test\"}";               JOutMessages outMessage = new JOutMessages(this.message.ip,outString);        outMessage.insert();             }      } 

1. Клиента посылает на сервер json строку c названием вызываемой задачи.
2. Задача извлекает переменные из сообщения и посылает ответ.

Задача
Задача должна быть создана в папке tasks и унаследованна от JClientTask.
В конструкторе должна передаваться класс JInMessages с входящим сообщением.
Должны быть реализованы методы rules,rights,action.
в rules описаны правила валидации переменных, можно написать свои правила валидации.
в rights перечисление прав пользователей которые имеют право вызывать действие.
в action основной код.

Извлечение переменных

 String message   = this.message.json.get("message").toString(); 

Строка ответа и поставнока в очередь

String outString = "{\"message\":\"Test\"}";        JOutMessages outMessage = new JOutMessages(this.message.ip,outString); outMessage.insert();

Вместо ip можно ставить любой ip который слушает сокет и ждет json строку.

Модели
После установки фремворка по инструкции в базе будут 2 таблицы: Users, Session. Примеры использования есть в папках с задачами.
Все модели должны быть созданы в папке models, унаследованы от DBQuery в котором реализовано подключение к базе данных и основные методы. В классе модели должна быть реализована логика взаимодействия с базой данных.

Права пользователей

1. Права должны быть описаны в задачах в методе rights:guest,user,admin. Неавторизованный пользовател имеет права guest. Зарегистрированнному пользователю присваивается user, эти значения хранятся в базе данных в таблице rights.
Пример: авторизация по токену, модели, права
Получение токена

@Override     public void action(){                  String email    = this.message.json.get("email").toString();                  String password = this.message.json.get("password").toString();                  Users users     = new Users();                  boolean isAuth  = users.authorization(email,password);                  String outString;                  if(isAuth){                            String token       = users.getToken();              int   userId       = users.id;                            String ip          = this.message.ip;                            //System.out.println(insertQuery);                            Session session = new Session();                            session.setToken(userId, token,ip);                                          outString = "{\"token\":\"" + token +"\"}";                       }else{              outString = "{\"error\":\"Incorrect login or password \"}";         }                  JOutMessages outMessage = new JOutMessages(this.message.ip,outString);         outMessage.insert();              } 

1. В права указываем ожидаемые переменные:email,password.
2. Создаем модель Users, вызываем метод авторизации.
3. Создаем модель сессии — получаем токен.
4. Отправляем ответ.
5. Токен сохраняем на клиенте.

Пример проверки прав

  @Override     public void action(){         /**          * get ip from session and send to open socket                  **/         System.out.println("user_id: " + webUser.id + " email: " + webUser.email + " rights: "+ webUser.rights);                   Session session = new Session();         session.findByUserID(12);                  String ip = session.ip;         //all users         //session  connection                  String outString = "{\"ip_message\":\"send to user by session id\"}";                  JOutMessages outMessage = new JOutMessages(ip,outString);         outMessage.insert();              } 

1. В правах указываем user.
2. В ожидаемых переменных token

После вызова задачи с токеном и правами «не гость». Пользователь ищется в базе данных в таблице Session, по user_id создается модель Users — которая доступнав задаче в переменной webUser.

Можно отправлять сообщения всем клиентам по user_id в Session или по соединениею в классе JConnections.

Пример регистрации можно посмотреть в классе tasks.JRegistrationTask
Все тесты находятся в папке /tests/.
Более подробные примеры можно посмотреть по ссылкам в начале сообщения.
ссылка на оригинал статьи https://habrahabr.ru/post/318782/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *