Всем доброго времени суток. Разрабатываю онлайн 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
> jsock.doc

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

Клиент:

//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/. Более подробные примеры можно посмотреть по ссылкам в начале сообщения.
Поделиться с друзьями
-->

Комментарии (10)


  1. laphroaig
    29.12.2016 21:16
    +4

    Иван, а вы пробовали свои предыдущие статьи перечитывать и комментарии к ним, чтобы хотя-бы ограниченно понять, почему они все без исключения в минус уходят? Упорство и труд все перетрут, но не в данном случае, когда есть упорство, но нет труда


    1. Padaboo
      29.12.2016 21:34
      -1

      Может быть я не мастер выражаться и оформлять текст, но постарался передать мысль макимальном емко, понятно и без лишних слов. Работает нормально.


      1. laphroaig
        29.12.2016 21:43
        +2

        ok


  1. sleeply4cat
    29.12.2016 22:48
    +2

    0_о


  1. fogone
    30.12.2016 15:17
    +1

    image


  1. tigraboris
    30.12.2016 17:50

    Да да ад… именно так все онлайн игры и работают.


    1. Padaboo
      30.12.2016 17:51

      Я смотрел много реализаций. Тут можно привязку к играм не делать — многопоточный асинхронный сервер.


      1. Yag0andy2006
        31.12.2016 23:03

        Akka


        1. Padaboo
          01.01.2017 21:12

          Akka- http?
          Мне нужен tcp/udp


          1. Yag0andy2006
            02.01.2017 13:42

            http://doc.akka.io/docs/akka/snapshot/scala/io-tcp.html
            http://doc.akka.io/docs/akka/current/scala/io-udp.html