質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

1997閲覧

【ソケット通信】サーバーとクライアント間で二次元配列の情報を送受信する方法

anpan___

総合スコア28

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/04/03 04:35

サーバーとクライアントで二次元配列のデータ(int[][]board)を送りたいと考えていますが、
キャストのをする必要があるのか、boardをフィールドにおいているからなのか、サーバーからクライアントに情報を送信できていない状態です…。

クライアントからサーバーのタイミングも同様のエラーが発生し、
送信側は、NumberFormatException、受信側はそのデータが受け取れずNullPointerExceptionが発生してしまいます。

サーバークライアント間で二次元配列をやり取りする方法を教えていただければ幸いです。
Communicatorクラスにおけるsend(int[][])/receveboardでエラーが発生している現状です。

また現状のコードの該当箇所はこちらです。

java

1class Communicator implements AutoCloseable { 2 private BufferedReader reader; 3 private PrintWriter out; 4 5 Communicator(Socket s) throws IOException { 6 try { 7 reader = new BufferedReader(new InputStreamReader(s.getInputStream())); 8 out = new PrintWriter(s.getOutputStream(), true); 9 } catch (IOException e) { 10 close(); 11 } 12 } 13 14 void send(Point point) throws IOException { 15 out.println(point.col + "," + point.row); 16 } 17 18 void send(int[][] board) throws IOException { 19 out.println(board); 20 } 21 22 Point receive() throws IOException { 23 String line = reader.readLine(); 24 if (line == null) 25 return null; 26 String[] tokens = line.split(","); 27 return new Point(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1])); 28 } 29 30 @Override 31 public void close() throws IOException { 32 if (out == null) { 33 out.close(); 34 out = null; 35 } 36 if (reader == null) { 37 reader.close(); 38 reader = null; 39 } 40 } 41 42 public int[][] receiveboard() throws IOException { 43 String board = reader.readLine(); 44 int[][] board2 = new int[8][8]; 45 if (board == null) { 46 return null; 47 } 48 String[] board1 = board.split(","); 49 for (int i = 0; i < 8; i++) { 50 for (int j = 0; j < 8; j++) { 51 board2[i][j] = Integer.parseInt(board1[i * 8 + j]); 52 } 53 } 54 return board2; 55 } 56 57 58}

java

1class Servers { 2 3 static int[][] board = { //盤面 0=無し 1=黒 2=白 3=置ける 4 { 0, 0, 0, 0, 0, 0, 0, 0 }, 5 { 0, 0, 0, 0, 0, 0, 0, 0 }, 6 { 0, 0, 0, 0, 0, 0, 0, 0 }, 7 { 0, 0, 0, 1, 2, 0, 0, 0 }, 8 { 0, 0, 0, 2, 1, 0, 0, 0 }, 9 { 0, 0, 0, 0, 0, 0, 0, 0 }, 10 { 0, 0, 0, 0, 0, 0, 0, 0 }, 11 { 0, 0, 0, 0, 0, 0, 0, 0 } }; 12 13 public void runServer() { 14 ResourceBundle rb = ResourceBundle.getBundle("Pro"); 15 System.out.println("クライアントの接続待ち"); 16 try (ServerSocket ss = new ServerSocket(Integer.parseInt(rb.getString("server_port"))); 17 Communicator comm = new Communicator(ss.accept());) { 18 System.out.println("ゲームスタート"); 19 Point point = null; 20 while (true) { 21 point = comm.receive(); 22 comm.receiveboard(); 23 System.out.println("Client: 受信=" + point); 24 25 printboard(board); 26 27 comm.send(point); 28 comm.send(board); 29 30 } //mainループ 31 } catch (Exception e) { 32 e.printStackTrace(); 33 } finally { 34 } 35 } 36 } 37 38 39 40public class Server { 41 public static void main(String[] args) { 42 Servers sc = new Servers(); 43 sc.runServer(); 44 } 45} 46

java

1class Clients extends Servers { 2 void runClient() { 3 ResourceBundle rb = ResourceBundle.getBundle("Pro"); 4 System.out.println("サーバーの接続待ち"); 5 try (Communicator comm = new Communicator( 6 new Socket(rb.getString("server_id"), Integer.parseInt(rb.getString("server_port"))));) { 7 System.out.println("ゲームスタート"); 8 Point point = null; 9 while (true) { 10 System.out.println("Server: 送信=" + point); 11 comm.send(point); 12 comm.send(board); 13 14 point = comm.receive(); 15 comm.receiveboard(); 16 } 17 } catch (Exception e) { 18 e.printStackTrace(); 19 } finally { 20 } 21 } 22 } 23} 24 25public class Client { 26 public static void main(String[] args) { 27 Clients s2 = new Clients(); 28 s2.runClient(); 29 } 30}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

送受信しているモノが何なのかをイメージ出来ておられないように思います.

Point の送受信が出来ているのは, send(Point) の

out.println(point.col + "," + point.row);

という処理と Point receive() の

String line = reader.readLine(); String[] tokens = line.split(","); new Point(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1]));

という処理の間で「"X,Y<改行>" という文字列の生成・送受信・Pointオブジェクト化」の流れが出来ているからです.

これは例えば,

Point p = new Point(1,2); System.out.println(point.col + "," + point.row);

とすると
1,2<改行>
と表示されることで送られる文字列を確認出来ますし,

String line = "1,2"; String[] tokens = line.split(","); Point p = new Point(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1])); System.out.println(p);

とすると p の中身が [1,2] であると表示されることで確認出来ます.

然るに, お作りになった send(int[][]) で out.println している内容を System.out.println で表示してみたら何が出るでしょうか. (その表示内容そのものが送信されています.)
int[][] receiveboard() の readLine() 部分をその表示内容にしたら board を再現できるでしょうか.

どんな文字列を送受信すれば board を再現できるかをお考えください.

#追記
文字列の送受信が出来ていれば, 以下のように2次元配列←→文字列の変換メソッドを用意することでやり易くなるかと思います.

java

1package teratail.q246663; 2 3public class ArrayToStringText { 4 public static void main(String[] args) { 5 int[][] board1 = new int[8][8]; 6 board1[3][3] = board1[4][4] = 1; 7 board1[3][4] = board1[4][3] = 2; 8 board1[2][4] = board1[3][5] = board1[4][2] = board1[5][3] = 3; 9 10 print("board1 -----",board1); 11 12 System.out.println("line -----"); 13 String line = createString(board1); 14 System.out.println(line); 15 16 int[][] board2 = createArray2D(line); 17 print("board2 -----",board2); 18 } 19 static void print(String label, int[][] array) { 20 System.out.println(label); 21 for(int i=0;i<array.length; i++) { 22 for(int j=0; j<array[i].length; j++) 23 System.out.print(array[i][j]); 24 System.out.println(); 25 } 26 } 27 28 /** 29 * 2次元配列を数字列化.<br> 30 * array2D.length と array2D[i].length が同じで無い場合, array2D[i].length の方が小さければ例外が発生するが, 31 * 大きい場合は i >= array2D.length の範囲のデータは無視される. 32 * @param array2D 2次元配列 33 * @return 文字列化した配列データ 34 */ 35 static String createString(int[][] array2D) { 36 int w = array2D.length; //一辺の大きさ 37 int size = (int)Math.pow(w,2); //全体の大きさ 38 StringBuilder sb = new StringBuilder(size); 39 for(int i=0; i<size; i++) sb.append((char)('0'+array2D[i/w][i%w])); 40 return sb.toString(); 41 } 42 /** 43 * 数字列を2次元配列化. 44 * @param line 数字列 45 * @return 2次元配列 46 * @throws IllegalArgumentException 正方形にならない場合 47 */ 48 static int[][] createArray2D(String line) { 49 int w = (int)Math.sqrt(line.length()); //一辺の大きさ 50 if(Math.pow(w,2) != line.length()) throw new IllegalArgumentException(); //正方形のデータで無ければ例外 51 int[][] array2D = new int[w][w]; 52 for(int i=0; i<line.length(); i++) array2D[i/w][i%w] = line.charAt(i)-'0'; 53 return array2D; 54 } 55}

plain

1board1 ----- 200000000 300000000 400003000 500012300 600321000 700030000 800000000 900000000 10line ----- 110000000000000000000030000001230000321000000300000000000000000000 12board2 ----- 1300000000 1400000000 1500003000 1600012300 1700321000 1800030000 1900000000 2000000000

投稿2020/04/03 05:08

編集2020/04/04 06:24
jimbe

総合スコア13209

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

anpan___

2020/04/03 05:13

再三にわたりありがとうございます! 的確なアドバイス感謝いたします。 非常にわかりやすいです! 一度いただいたアドバイスを参考にコードを修正してみます。
guest

0

java.io.Serializable

Javaオブジェクトはjava.io.Serializableを実装することで、ネットワークに直接送受信することができます。そのためには、Reader/Writerではなく、java.io.ObjectInputStream/java.io.ObjectOutputStreamを使います。

PointとBoardクラスを定義します。java.io.Serializableを実装。フィールドの追加変更ごとにserialVersionUIDを変更すると(eclipseで手動生成)、シリアライズされたオブジェクトとクラスのバージョンが合わなければエラーにしてくれます。

Java

1import java.io.Serializable; 2 3public class Point implements Serializable { 4 private static final long serialVersionUID = -1802208115911716722L; 5 6 final int row; 7 final int col; 8 9 public Point(int row, int col) { 10 this.row = row; 11 this.col = col; 12 } 13 14 @Override 15 public String toString() { 16 return "row : " + row + ", col : " + col; 17 } 18 19}

配列int[][]はすでにSerializableを実装しているのでBoardクラスは不要ですが、toString()を使いたいのでクラスでラップしました。

Java

1import java.io.Serializable; 2import java.util.Arrays; 3 4public class Board implements Serializable { 5 private static final long serialVersionUID = 3430989485426974264L; 6 7 int[][] board = { // 盤面 0=無し 1=黒 2=白 3=置ける 8 { 0, 0, 0, 0, 0, 0, 0, 0 }, 9 { 0, 0, 0, 0, 0, 0, 0, 0 }, 10 { 0, 0, 0, 0, 0, 0, 0, 0 }, 11 { 0, 0, 0, 1, 2, 0, 0, 0 }, 12 { 0, 0, 0, 2, 1, 0, 0, 0 }, 13 { 0, 0, 0, 0, 0, 0, 0, 0 }, 14 { 0, 0, 0, 0, 0, 0, 0, 0 }, 15 { 0, 0, 0, 0, 0, 0, 0, 0 } }; 16 17 @Override 18 public String toString() { 19 return toString(this.board); 20 } 21 22 static String toString(int[][] board) { 23 String tbl = "["; 24 for (int[] row : board) { 25 tbl += ((tbl.length() <= 1) ? "" : ",") + Arrays.toString(row); 26 } 27 return tbl + "]"; 28 } 29 30}

クライアントとサーバーの送受信の例です。送信時にObjectOutputStream.flush();は必須。しなければ、データがバッファにたまったままで送信されない

Java

1import java.io.IOException; 2import java.io.ObjectInputStream; 3import java.io.ObjectOutputStream; 4import java.net.ServerSocket; 5import java.net.Socket; 6 7public class Server_ { 8 public static void main(String[] args) { 9 Board board = new Board(); 10 Point point = new Point(20,59); 11 try (ServerSocket serverSock = new ServerSocket(6066)) { 12 try (Socket Sock = serverSock.accept(); 13 ObjectOutputStream out = new ObjectOutputStream(Sock.getOutputStream()); 14 ObjectInputStream in = new ObjectInputStream(Sock.getInputStream())) { 15 16 out.writeUTF("This is Board Server."); 17 out.flush(); 18 System.out.println(in.readUTF()); 19 20 out.writeObject(board); 21 out.writeObject(board.board); 22 out.writeObject(point); 23 out.flush(); 24 25 out.writeUTF("Good bye."); 26 out.flush(); 27 System.out.println(in.readUTF()); 28 } 29 } catch (IOException e) { 30 e.printStackTrace(); 31 } 32 } 33}

Java

1import java.io.IOException; 2import java.io.ObjectInputStream; 3import java.io.ObjectOutputStream; 4import java.net.Socket; 5 6public class Client_ { 7 public static void main(String[] args) { 8 try (Socket sock = new Socket("localhost", 6066); 9 ObjectOutputStream out = new ObjectOutputStream(sock.getOutputStream()); 10 ObjectInputStream in = new ObjectInputStream(sock.getInputStream())) { 11 12 out.writeUTF("This is Board Client."); 13 out.flush(); 14 System.out.println(in.readUTF()); 15 16 Board board = (Board)in.readObject(); 17 int[][] boardArray = (int[][])in.readObject(); 18 Point point = (Point)in.readObject(); 19 20 System.out.println(board); 21 System.out.println(Board.toString(boardArray)); 22 System.out.println(point); 23 24 out.writeUTF("Good bye."); 25 out.flush(); 26 System.out.println(in.readUTF()); 27 } catch (ClassNotFoundException e) { 28 e.printStackTrace(); 29 } catch (IOException e) { 30 e.printStackTrace(); 31 } 32 } 33}

投稿2020/04/04 10:11

編集2020/04/05 05:25
xebme

総合スコア1090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問