2つの異なるポートをリッスンしているサーバーがあり、接続が受け入れられた後、nameOfClient - Socketの組み合わせがhashMapに保存されます。 その後、ループ内のメソッドを起動して、どのクライアントがメッセージを送信しているのか、そして誰がそのメッセージの受信者であるのかを調べ、ハッシュマップからソケット値を取得し、それを使用してそのソケットへのDataOutputStreamを初期化します。JavaでwriteUTFとreadUTFで予期しない値が発生しました
問題は、サーバーが最初の2つのメッセージのみを受信し、奇妙な値が含まれていることです。例えば。クライアント1のwriteInt(1)をサーバに送信しますが、反対側では明らかにランダムな値が受信されます。データを送信する
クラスは次のとおりです。
public class Game {
List <Player> players = new ArrayList<Player>();
int size;
public Game() {
(...game code here...)
public void sendUpdatedTableValues(int nP, int nF, int nS, int sc)
{
/* string,byte,stringa,primitivo del messaggio
string - mittente; byte - tipo di messaggio; stringa - ricevente; prim - messaggio
*/
try {
DataOutputStream dataOut = new DataOutputStream(Lane.socket.getOutputStream());
dataOut.writeUTF("Pista " + Lane.laneNum);
dataOut.writeInt(1);
dataOut.writeUTF("Amministrazione");
dataOut.writeInt(nP);
dataOut.writeUTF("-");
dataOut.writeInt(nF);
dataOut.writeUTF("-");
dataOut.writeInt(nS);
dataOut.writeUTF("-");
dataOut.writeInt(sc);
dataOut.flush();
} catch (IOException ex) {
Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* This method send the player's number of strikes
* this method has ID byte = 3
* @param nP - Player Number
* @param nS - Strike Number
*/
public void sendStrikeCounter(int nP, int nS)
{
try {
DataOutputStream dataOut = new DataOutputStream(Lane.socket.getOutputStream());
dataOut.writeUTF("Pista " + Lane.laneNum);
dataOut.writeInt(3);
dataOut.writeUTF("Amministrazione");
dataOut.writeInt(nP);
dataOut.writeUTF("-");
dataOut.writeInt(nS);
dataOut.flush();
} catch (IOException ex) {
Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* This method updates result table on server
* this method has ID byte= 4
* @param nP - Player Number
* @param nF - Frame Number
* @param res - Frame result
*/
public void sendUpdatedResultsTable(int nP, int nF, int res)
{
try {
DataOutputStream dataOut = new DataOutputStream(Lane.socket.getOutputStream());
dataOut.writeUTF("Pista " + Lane.laneNum);
dataOut.writeInt(4);
dataOut.writeUTF("Amministrazione");
dataOut.writeInt(nP);
dataOut.writeUTF("-");
dataOut.writeInt(nF);
dataOut.writeUTF("-");
dataOut.writeInt(res);
dataOut.flush();
} catch (IOException ex) {
Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* This method send the player's number of spares
* this method has ID byte = 5
* @param nP - Player Number
* @param nS - Spare Number
*/
public void sendSpareCounter(int nP, int nS)
{
try {
DataOutputStream dataOut = new DataOutputStream(Lane.socket.getOutputStream());
dataOut.writeUTF("Pista " + Lane.laneNum);
dataOut.writeInt(5);
dataOut.writeUTF("Amministrazione");
dataOut.writeInt(nP);
dataOut.writeUTF("-");
dataOut.writeInt(nS);
dataOut.flush();
} catch (IOException ex) {
Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
}
}
サーバーのコードは次のとおりです。
public class Server {
public static List <Player> players = new ArrayList <Player>();
public static HashMap <String, List<Player>> laneHashMap = new HashMap<String, List<Player>>();
ServerSocket adminListener;
ServerSocket clientListener;
public static void main(String[] args) throws IOException {
System.out.println("Server bowling avviato:\n");
Server server = new Server();
/**
* The port 9090 is reserved for the admin client, the other port is
* used by all the lane clients
*/
server.adminListener = new ServerSocket(9090);
server.clientListener = new ServerSocket(9898);
int clientNumber = 1; //Used to keep track of every single lane
//Create an HashMap used to store the name and the socket of the clients
HashMap<String, Socket> socketMap = new HashMap<>();
/**
* The server starts two different threads that keep listening for
* incoming connections
*/
new threadAdminPort(server.adminListener, socketMap).start();
new threadClientPort(server.clientListener, socketMap, clientNumber).start();
}
/**
* Used to listen to port 9090
*/
private static class threadAdminPort extends Thread {
private ServerSocket adminListener;
private HashMap<String, Socket> socketMap;
public threadAdminPort(ServerSocket adminListener, HashMap<String, Socket> socketMap) {
this.adminListener = adminListener;
this.socketMap = socketMap;
}
@Override
public void run() {
try {
while (true) {
new Handler(adminListener.accept() , socketMap).start();
}
} catch (IOException e) {
System.out.println("Errore di accept: " + e);
} finally {
try {
adminListener.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
/**
* Used to listen to port 9898
*/
private static class threadClientPort extends Thread {
private ServerSocket clientListener;
private HashMap<String, Socket> socketMap;
private int clientNumber;
public threadClientPort(ServerSocket clientListener , HashMap<String, Socket> socketMap , int clientNumber) {
this.clientListener = clientListener;
this.socketMap = socketMap;
this.clientNumber = clientNumber;
}
@Override
public void run() {
try {
while (true) {
new Handler(clientListener.accept() , socketMap , clientNumber++).start();
}
} catch (IOException e) {
System.out.println("Errore di accept: " + e);
} finally {
try {
clientListener.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
/**
* A private thread to handle requests on a particular socket.
*/
private static class Handler extends Thread {
Socket socket;
HashMap<String, Socket> socketMap;
int clientNumber;
//Set true only if it is received a endOfGame message
boolean endOfGame = false;
/**
* This constructor is meant to be used by the lane clients.
*/
public Handler(Socket socket, HashMap<String, Socket> socketMap , int clientNumber) throws IOException {
this.socket = socket;
this.socketMap = socketMap;
this.clientNumber = clientNumber;
String clientName = "Pista " + clientNumber;
synchronized(socketMap) {
socketMap.put(clientName, socket);
}
//Send laneNum to the client
DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream());
dataOut.writeInt(clientNumber);
System.out.println("- Pista " + clientNumber + " connessa -\nPronta per giocare");
}
/**
* This constructor is meant to be used by the admin client as it
* provides no clientNumber variable.
*/
public Handler(Socket socket , HashMap<String, Socket> socketMap) {
this.socket = socket;
this.socketMap = socketMap;
String clientName = "Amministrazione";
synchronized (socketMap) {
socketMap.put(clientName, socket);
}
System.out.println("- Client Amministrazione connesso -");
}
/**
* This function is shared by both the admin client and the lane clients
*/
@Override
public void run() {
forwardMessage();
try {
socket.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
if(clientNumber==0)
System.out.println("Connessione con il client amministrazione terminata");
else
System.out.println("Connessione con il client " + clientNumber + " terminata");
}
private void forwardMessage() {
Set set = socketMap.entrySet();
Iterator iterator = set.iterator();
//The following are the fixed fields of a message
String sender = null;
String receiver = null;
int messageType = 100;
//while(iterator.hasNext())
while(true){
for(Map.Entry<String, Socket> entry : socketMap.entrySet()){
// Map.Entry mapEntry = (Map.Entry)iterator.next();
Socket tempRecSocket = (Socket) entry.getValue();
System.out.println("Il valore di tempRecSocket è "+ tempRecSocket);
DataInputStream dataIn;
DataOutputStream dataOut;
try {
dataIn = new DataInputStream(tempRecSocket.getInputStream());
//Analyze and understand what type of message it is and who is
//the sender and the receiver
sender = dataIn.readUTF();
messageType = dataIn.readInt();
System.out.println("Sender ricevuto "+ sender);
receiver = dataIn.readUTF();
System.out.println("Receiver ricevuto " + receiver);
switch (messageType) {
case 0:
{
//player 1
boolean start = dataIn.readBoolean();
String namezero = dataIn.readUTF();
int shoeszero = dataIn.readInt();
String cf = dataIn.readUTF();
//player 2
int shoesone = dataIn.readInt();
String nameone = dataIn.readUTF();
//player 3
int shoestwo = dataIn.readInt();
String nametwo = dataIn.readUTF();
//player 4
int shoesthree = dataIn.readInt();
String namethree = dataIn.readUTF();
//player 5
int shoesfour = dataIn.readInt();
String namefour = dataIn.readUTF();
//player 6
int shoesfive = dataIn.readInt();
String namefive = dataIn.readUTF();
laneHashMap.put(receiver, players); //insert in hashmap lane data
laneHashMap.get(receiver).add(new Player(0,namezero,shoeszero,cf)); //add player0 in players list7
laneHashMap.get(receiver).add(new Player(1,shoesone,nameone));
laneHashMap.get(receiver).add(new Player(2,shoestwo,nametwo));
laneHashMap.get(receiver).add(new Player(3,shoesthree,namethree));
laneHashMap.get(receiver).add(new Player(4,shoesfour,namefour));
laneHashMap.get(receiver).add(new Player(5,shoesfive,namefive));
Socket tempSndSocket = (Socket) socketMap.get(receiver);
System.out.println("Il valore di tempSndSocket è "+ tempSndSocket);
dataOut = new DataOutputStream(tempSndSocket.getOutputStream());
dataOut.writeUTF(sender);
dataOut.writeInt(messageType);
if(messageType!=0)
System.out.println("Valore di messageType "+ messageType);
dataOut.writeUTF(receiver);
dataOut.writeBoolean(start);
for (int i = 0;i<6;i++)
{
laneHashMap.get(receiver).get(i).setInitialTable();
dataOut.writeUTF(laneHashMap.get(receiver).get(i).getName());
dataOut.writeInt(0); //separatore
} dataOut.flush();
// dataOut.close();
System.out.println("Il server ha inviato correttamente il messaggio di tipo 0");
break;
}
case 1:
{
System.out.println("Il server ha ricevuto correttamente il messaggio di tipo 1 ed ora provvederà all'invio");
//sendUpdatedTableValues
int playerNumber = dataIn.readInt();
dataIn.readUTF();
int frameNumber = dataIn.readInt();
dataIn.readUTF();
int shotNumber = dataIn.readInt();
dataIn.readUTF();
int score = dataIn.readInt();
System.out.println("Ho ricevuto: 1 - "+ playerNumber + "2 - framenumber "+ frameNumber+ "3 - shotNumber" + shotNumber+ "4 - score "+ score);
//update local player data
laneHashMap.get(sender).get(playerNumber).setTable(frameNumber, shotNumber, score);
System.out.println("In questo turno il giocatore ha totalizzato "+ laneHashMap.get(sender).get(playerNumber).getTable(frameNumber, shotNumber));
Socket tempSndSocket = (Socket) socketMap.get(receiver);
dataOut = new DataOutputStream(tempSndSocket.getOutputStream());
dataOut.writeUTF(sender);
dataOut.writeInt(messageType);
dataOut.writeUTF(receiver);
dataOut.writeInt(playerNumber);
dataOut.writeUTF("-");
dataOut.writeInt(frameNumber);
dataOut.writeUTF("-");
dataOut.writeInt(shotNumber);
dataOut.writeUTF("-");
dataOut.writeInt(score);
break;
}
break;
}
別のクラスには、サーバに接続しGame.javaの同一パッケージ内にあります。ゲームは別のクライアントによって正常に開始された後、メッセージを正しく受信できません。
私は何かが間違っているかもしれませんが、あなたは5の整数と5つの文字列を書いている間に4つの整数と3つの文字列を読んでいます。これは完全なコードではありません(もしそうなら、完全なコードを投稿してください)か、それはあなたの問題かもしれません。 – n247s
stringの場合はstringを、intの場合はintを読み込む必要があります。文字列をint型として読み込むと、ゴミが出ます。そして、バイナリ形式を書いているので、テキスト形式を追加することにはあまり効果がありません。私はそれを落とすだろう。 –
あなたの書き込みがバッファされないので(おそらくそうするべきです)、 'flush()'を実行すると、フラッシュするバッファがないので何もしません。 –