スマフォアプリ(java/kotlin/Swift/Unity)からサーバ(java)のmariadbを操作する.4
●前提
同時接続は多数
サーバ言語:java+mariaDB+JDBCドライバ
MySQLのrootユーザー名root,passwordは1234abcde
クライアント言語:android-java/android-kotlin/iOS-Swift/unityC#
通信ポート:3456
今回はサーバのJavaの強化をします。
新規のスコアと名前の登録、指定された順位から指定した人数分のスコアと名前の取得です。
csvのパーサですが、javaなら.split()、C++ならboostとかでcsvパーシングしても良かったのですが、今回必要な物は単純な物なので手で組んだ物と、splitで分割した物の2通りが入っていますが、正規表現でエラーチェックしているのでsplitだけで良いと思います。あくまでも例です。
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]でユーザー情報をスコアの高い順から全部出力\n2,num1,num2[enter]でnum1番目からnum2人分出力\n3,nun,name[enter]で得点numでnameを登録\nただの[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 if( input.matches("2,[1-9][0-9]{0,},[1-9][0-9]{0,}") ){
System.out.println("2が入力されました。指定された順位から指定された人数分のスコアを表示します");
System.out.println(line);
} else if( input.matches("3,[1-9][0-9]{0,},[^ ]{1}.{1,999}") ){
System.out.println("3が入力されました。スコアを登録しました");
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.util.ArrayList;
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,id ASC");
String line="";
// rs.next()はこのカラムがあるかだけでは無く、次のカラムに移動させるので、このような方法をとっています。
int c=0;
while(rs.next()){
c++;
line += "," + "id:" + rs.getInt("id") + ":name=" + rs.getString("name") + ":score=" + rs.getInt("score");
}
outLines = c + line;
rs.close(); // close
stm.close(); // close
return outLines;
} catch (SQLException e) {
System.out.println("MySQL(mariaDB)に接続できませんでした3");
}
return outLines;
}
//
// 指定された順位から指定された人数分を、スコア順に取得する(スコアと名前だけをcsv形式で、先頭に人数が入ります)
//
public static String getScoreRankNum( String outLines,int top,int count ) {
// top(1org)からcount(1org)分取得する。
if( (top<1) || (count<1) ){
outLines="0";
return outLines;
}
try {
//
// データを取得するには Statement を作成して executeQuery() でSQL文を投げると ResultSet の object で返ってくる
//
Statement stm = con.createStatement();
ResultSet rs = stm.executeQuery("SELECT * FROM hiscore ORDER BY score DESC,id ASC");
String line="";
// rs.next()はこのカラムがあるかだけでは無く、次のカラムに移動させるので、このような方法をとっています。
int c=0;
int outCount=0;
while(rs.next() && count!=0 ){
c++;
if(c>=top){
line += "," + rs.getInt("score") + "," + rs.getString("name");
count--;
outCount++;
}
}
outLines = outCount + line;
rs.close(); // close
stm.close(); // close
return outLines;
} catch (SQLException e) {
System.out.println("MySQL(mariaDB)に接続できませんでした3");
}
return outLines;
}
//
// スコアと名前をデータベースに登録
//
public static void insertScore( int score, String name) {
String insert = "INSERT INTO hiscore (name,score) VALUES('" + name + "'," + score + ")";
if(!execUpdate(insert)){
System.out.println("追加出来ませんでした");
}
}
/*
//
// だれもデータベースに登録されていない場合、とりあえず一人分追加します、
//
private static void initScore() {
if(!execUpdate("INSERT INTO hiscore (name,score) VALUES('けんぢ',1)")){
System.out.println("追加出来ませんでした");
}
}
*/
}
//----------------------------------------------------------------------------
class MiniCSV {
//
// 簡短なcsvをArrayListにするクラス(簡易版)
//
private static final char SEPARATOR = ',';
public static int getCSV(ArrayList csvData,String str){
char tmp;
char SEPARATOR = ',';
int csvCount = 0;
int strCount = 0;
int strLen = str.length();
while(strLen>strCount){
StringBuffer sb = new StringBuffer();
while(strLen>strCount){
tmp = str.charAt(strCount);
strCount++;
if(tmp==SEPARATOR) break;
sb.append(tmp);
}
csvCount++;
csvData.add(sb.toString());
}
return csvCount;
}
}
//----------------------------------------------------------------------------
//
// ソケットサーバとマルチスレッドでの待ち受け(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 if(line.matches("2,[1-9][0-9]{0,},[1-9][0-9]{0,}") ){
// 正規表現をくぐり抜けているので、パラメータ(line)にエラーは無いものとする。
// オリジナルのcsvパーサを使った方
ArrayList csvData = new ArrayList();
MiniCSV.getCSV(csvData,line);
line="";
line = SqlCtl.getScoreRankNum(line,Integer.parseInt(csvData.get(1)),Integer.parseInt(csvData.get(2)));
out.println(line);
System.out.println(socket.getRemoteSocketAddress() + " 送信:" + line);
}else if(line.matches("3,[1-9][0-9]{0,},[^ ]{1}.{1,999}") ){
// 正規表現をくぐり抜けているので、パラメータ(line)にエラーは無いものとする。
// splitで分割した方
String[] csvData = line.split(",");
line = "scoreが" + csvData[1] + "の" + csvData[2] + "さんを登録します";
SqlCtl.insertScore( Integer.parseInt(csvData[1]),csvData[2] );
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;
}
}
}
次はandroid-javaからのアクセスとJAVAサーバ/JAVAクライアントの修正をします。
戻る