Вообще изначальная задача - написать игру с двумя игроками, что-то типа точек.
т.е. один игрок (клиент) делает ход, отправляет данные (координаты x и y) на сервер. Сервер обрабатывает эту информацию и отправляет сообщение с какими-то данными всем подключенным клиентам. Все это надо реализовать на сокетах.
За основу взяла реализацию чата, но мне удобнее передавать объекты, поэтому использую ObjectInputStream и ObjectOutputStream.
Написала пример: клиент вводит координаты x y, отправляет на сервер. На сервере хранится матрица А. Получаем от клиента x,y, присваиваем A[x][y]=1, отправляем всем клиентам объект класса ServerAnswer (матрица, x,y). Клиент получает и выводит матрицу.
Для начала запускаю только один клиент. Первый раз все работает, но когда я ввожу новые координаты на клиенте, они отправляются на сервер, он посылает ответ и на клиенте при попытке выполнения -
sa = (ServerAnswer)ois.readObject();
вылетает ошибка
апр 17, 2014 12:06:45 PM client2.SocketInputThread run
SEVERE: null
java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1377)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at client2.SocketInputThread.run(SocketInputThread.java:37)
at java.lang.Thread.run(Thread.java:744)
Подскажите. пожалуйста, что не так в коде.
Код Сервера:
public class Server2 {
public static void main(String[] args) {
System.out.println("Program starting...");
try {
ServerSocket ss = new ServerSocket(3129,0,
InetAddress.getByName("localhost"));
System.out.println("Server starting...");
while(true){
Socket s = ss.accept(); // ожидание новых клиентов
SocketThread socketThread = new SocketThread(s);
Thread t = new Thread(socketThread);
t.start(); // запуск нового потока для каждого нового клиента
}
} catch (IOException ex) {
Logger.getLogger(Server2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Класс SocketThread:
public class SocketThread implements Runnable {
private Socket s = null;
private boolean exit = true;
private int x = -1;
private int y = -1;
private int p = 0;
private int [][]A;
private ArrayList
public SocketThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
System.out.println("User connect...");
ListSocket.addSocketToList(s); // добавление текущого сокета с глобальной список сокетов
InputStream in = s.getInputStream();
ois = new ObjectInputStream(in);//получаем от игрока новое ребро
A = new int [5][5];
for (int i = 0; i<5; i++)
for (int j = 0; j < 5; j++)
{
A[i][j] = 0;
}
while (s.isConnected()) {
Para new_p = (Para)ois.readObject();
x = new_p.X();
y = new_p.Y();
p = new_p.P();
A[x][y] = p;
System.out.println(x + ";" + y);
ServerAnswer sa = new ServerAnswer(5, 5);
sa.SetAns(new_p, A);
listSocket = ListSocket.getListSocket();
for (Socket socket : listSocket) { // отсылка сообщения всем сокетам
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(sa);
oos.flush();
}
}
ListSocket.removeSocketWithList(s); // если поток завершается то сокет
клиента удаляется из списка сокетов
System.out.println("User disconnect...");
} catch (IOException ex) {
try {
s.close();
} catch (IOException ex1) {
Logger.getLogger(SocketThread.class.getName()).log(Level.SEVERE, null, ex1);
}
Logger.getLogger(SocketThread.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(SocketThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Клиент:
public class Client2 {
public static void main(String[] args) {
try {
System.out.println("Client starting...");
Socket s = new Socket("localhost",3129);
System.out.println("Connect to server...");
Thread threadIn = new Thread(new SocketInputThread(s));// создание отдельного
потока на считывание даных от сервера
Thread threadOut = new Thread(new SocketOutputThread(s));// создание
отдельного потока на ввод даных с клавиатуры
threadIn.start();
threadOut.start();
} catch (UnknownHostException ex) {
Logger.getLogger(Client2.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Client2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
SocketInputThread:
public class SocketInputThread implements Runnable {
private Socket s = null;
private ObjectInputStream ois = null;
public SocketInputThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
InputStream in = s.getInputStream();
ois = new ObjectInputStream(in);
while(true){
ServerAnswer sa;
sa = (ServerAnswer)ois.readObject();
String str = "";
for (int i=0; i
public SocketOutputThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
Scanner sc = new Scanner(System.in);
oos = new ObjectOutputStream(s.getOutputStream());
while (true) {
int x = sc.nextInt();
int y = sc.nextInt();
Para p = new Para();
p.SetPara(x,y,1);
oos.writeObject(p);
oos.flush();
}
} catch (IOException ex) {
Logger.getLogger(SocketOutputThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Ответ
На один ObjectOutputStream должен приходиться ровно один ObjectInputStream Поясню: Корректный object stream выглядит так: [stream header], [object], [object], [object],... У вас object stream'ы выглядят так: [stream header], [object], [object], [stream header], [object], ... Stream header записывается каждый раз при создании нового ObjectOutputStream. Ваш invalid type code: AC означает, что ObjectInputStream ожидал прочитать объект, а прочитал хидер начала потока. То есть ошибка тут: for (Socket socket : listSocket) { // отсылка сообщения всем сокетам oos = new ObjectOutputStream(socket.getOutputStream()); Нужно хранить не список сокетов, чтобы каждый раз, проходясь по ним, создавать новые ObjectOutputStream'ы, а хранить список ObjectOutputStream'ов и переиспользовать их.
Комментариев нет:
Отправить комментарий