スマフォアプリ(java/kotlin/Swift/Unity)からサーバ(java)のmariadbを操作する.3
●前提
同時接続は多数
サーバ言語:java+mariaDB+JDBCドライバ
MySQLのrootユーザー名root,passwordは1234abcde
クライアント言語:android-java/android-kotlin/iOS-Swift/unityC#
通信ポート:3456
では、firewall-cmdでポートの開放をしましょう。3456番ポートですね。
# firewall-cmd --zone=public --add-port=3456/tcp --permanent
# firewall-cmd --reload
今回はSQLにサーバのJavaから代理でクエリを出して、その結果を得るだけなので、マルチスレッドにする必要性はそれほどありませんが、今後のためにマルチスレッド化します。
これを発展させればチャットやロビー、ゲームサーバ、在庫管理サーバなども作れると思いますが、C#のREFとかポインタ渡しが出来ない言語だときついですね。
スコアの順序は高い人からでカンマで区切って出力しています。csv形式ですね。
ScoreServerを起動した状態で無いとScoreClientは実行できません。
ScoreClientのコンパイルは、
javac ScoreClient.java
で、実行は、
java ScoreClient
です。ScoreServerの方のコンパイルと実行は変わっていません。本来ならばファイルを分けないと行けませんが、サンプルなので一本で書きました。(classはたくさん使ってますが^^;)
[ScoerClient.java]
import java.net.Socket;
import java.net.ServerSocket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.IOException;
public class ScoreClient {
    public static final String SERVER_URL = "219.117.194.51";         // うちの会社のIPアドレス。"localhost" とかでも実験は出来ます
    public static final int SOCKET_PORT = 3456;
    public static void main(String args[]) {
        Socket socket = null;
        try {
            System.out.println("接続します");
            socket = new Socket(SERVER_URL, SOCKET_PORT);
            System.out.println("接続しました" + socket.getRemoteSocketAddress());
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader keyIn = new BufferedReader(new InputStreamReader(System.in));
            String input;
            System.out.println("[1][enter]でハイスコアを、ただの[enter]で終了します。");
            while ( (input = keyIn.readLine()).length() > 0 ) {
                out.println(input);
                String line = in.readLine();
                if (line != null) {
                    if( input.equals("1")){
                        System.out.println("1が入力されました。ハイスコアを表示します");
                        System.out.println(line);
                    } else {
                        System.out.println(line);
                    }
                } else {
                    System.out.println("[enter]だけが入力されたので終了します");
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socket != null) {
                    socket.close();
                    socket=null;
                }
            } catch (IOException e) {}
            if(socket!=null) System.out.println("切断されました " + socket.getRemoteSocketAddress());
        }
    }
}
[ScoerServe.java]
import java.sql.*;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.IOException;
//
// ハイスコアの管理サーバ(ctl+cで終了)
//
//----------------------------------------------------------------------------
class SqlCtl {
//
// sql control class
//
    static Connection con = null;
    private static final String MYSQL_URL = "jdbc:mysql://localhost:3306/test906";    // 接続するMySQLのURL(ローカルホスト:madiadb/MySQLは3306番ポート)
    private static final String MYSQL_USR = "root";                                   // MySQLのユーザー名
    private static final String MYSQL_PASS = "1234abcde";                             // MySQLのユーザーのパスワード
    //
    // MySQL(mariaDB)に接続
    //
    public static boolean openSQL() {
        try {
            // mariaDBへ接続するためにJDBCドライバ読み込む
            Class.forName("org.mariadb.jdbc.Driver").newInstance();
            // 接続する
            con = DriverManager.getConnection(MYSQL_URL, MYSQL_USR,MYSQL_PASS);
            System.out.println("MySQL(mariaDB)に接続できました");
            return true;
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            System.out.println("JDBCドライバのロードに失敗しました");
        } catch (SQLException e) {
            System.out.println("MySQL(mariaDB)に接続できませんでした");
            if (con != null) {
                try {
	                con.close();
	                con=null;
                } catch (SQLException ex) {
        	        System.out.println("MySQL(mariaDB)のCloseに失敗しました");
		}
            }
        }
        return false;
    }
     //
     // 値を返さないsqlクエリを実行
     //
     private static boolean execUpdate(String sql) {
        try {
            Statement stm = con.createStatement();
            stm.executeUpdate(sql);
            stm.close();   // close
            return true;
        } catch (SQLException e) {
            return false;
        }
     }
    //
    // スコア順に表示する
    //
    public static String getScoreRank( String outLines ) {
        try {
            //
            // データを取得するには Statement を作成して executeQuery() でSQL文を投げると ResultSet の object で返ってくる
            //
            Statement stm = con.createStatement();
            ResultSet rs = stm.executeQuery("SELECT * FROM hiscore ORDER BY score DESC");
            // rs.next()はこのカラムがあるかだけでは無く、次のカラムに移動させるので、このような方法をとっています。
            boolean f=false;
            while(rs.next()){
                f=true;
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int score = rs.getInt("score");
                outLines += "id:" + id + ":name=" + name + ":score=" + score + ",";
            }
            if(f==false){
                System.out.println("データがありませんので一人分追加します");
                initScore();
            }
            rs.close();    // close
            stm.close();   // close
            return outLines;
        } catch (SQLException e) {
            System.out.println("MySQL(mariaDB)に接続できませんでした3");
        }
        return outLines;
    }
    //
    // だれもデータベースに登録されていない場合、とりあえず一人分追加します、
    //
    private static void initScore() {
        if(!execUpdate("INSERT INTO hiscore (name,score) VALUES('けんぢ',1)")){
            System.out.println("追加出来ませんでした");
        }
    }
}
//----------------------------------------------------------------------------
//
// ソケットサーバとマルチスレッドでの待ち受け(ctl+cで終了)
//
class MultiSocket {
    public static final int SOCKET_PORT = 3456;
    public static boolean socketMain() {
        // serversocket
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(SOCKET_PORT);
            System.out.println("サーバーが起動しました(port="+ serverSocket.getLocalPort() + ")");
            System.out.println("サーバーを終了する場合は ctrl+c で終了させて下さい");
            // 待ち受け(ctrl+cで終了)
            while (true) {
                Socket socket = serverSocket.accept();          // 待ち受け許可
                new ScoreThread(socket).start();                // クライアントに接続されたらスレッド作成
            }
         } catch (IOException e) {
             e.printStackTrace();
         } finally {
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                    serverSocket = null;
                 }
            } catch (IOException e) {}
        }
        return false;
    }
}
//----------------------------------------------------------------------------
//
// スレッド
//
class ScoreThread extends Thread {
    private Socket socket;
    public ScoreThread(Socket socket) {
        this.socket = socket;
        System.out.println("接続されました " + socket.getRemoteSocketAddress());
    }
    // run()は自動的に実行される
    public void run() {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            String line;
            while ( (line = in.readLine()) != null ) {
                System.out.println(socket.getRemoteSocketAddress() + " 受信:" + line);
                // クライアントから1が入力された場合はハイスコア表示
                if(line.equals("1")){
                    line="";
                    line = SqlCtl.getScoreRank(line);
                    out.println(line);
                    System.out.println(socket.getRemoteSocketAddress()  + " 送信:" + line);
                } else {
                      out.println(line+"は間違ったコマンドです");
                      System.out.println(socket.getRemoteSocketAddress()  + " 送信(error-cmd): " + line);
                }
            }
            System.out.println("クライアントは終了しました" + socket.getRemoteSocketAddress());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socket != null)  {
                    socket.close();
                    socket=null;
                }
            } catch (IOException e) {}
            if(socket!=null) {
                 System.out.println("切断されました" + socket.getRemoteSocketAddress());
                 socket=null;
            }
        }
    }
}
//----------------------------------------------------------------------------
//
// メイン
//
public class ScoreServer {
    public static void main(String[] args) {
        // データベースへ接続する
	if(!SqlCtl.openSQL()){
            System.out.println("データベースに接続できませんでした");
            return;
        }
        // マルチクライアントソケットサーバの起動
	if(!MultiSocket.socketMain()){
            System.out.println("マルチクライアントソケットサーバの起動に失敗しました");
            return;
        }
    }
}
次はサーバの機能強化を行います
戻る