#java #sockets #io #stream #client-server
#java #сокеты #io #поток #клиент-сервер
Вопрос:
Как мне сохранить сервер «открытым», чтобы он мог отправлять и получать объекты на постоянной основе без сбоев? В принципе, я хотел бы создать бесконечный цикл вокруг readRecord
метода, чтобы он выполнялся бесконечно.
сервер:
package net.bounceme.dur.driver;
import java.net.*;
import java.io.*;
import java.util.Properties;
import java.util.logging.Logger;
public class Server {
private static final Logger log = Logger.getLogger(Server.class.getName());
private final RecordQueue recordsQueue = new RecordQueue();
public static void main(String[] args) throws IOException {
Properties props = PropertiesReader.getProps();
int portNumber = Integer.parseInt(props.getProperty("port"));
new Server().readRecord(portNumber);
}
public void readRecord(int portNumber) throws IOException {
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket socket = serverSocket.accept();
ObjectOutputStream objectOutputStream = null;
MyRecord recordFromClient = null;
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
while (true) {
try {
recordFromClient = (MyRecord) objectInputStream.readObject();
} catch (ClassNotFoundException e) {
System.out.println(e);
}
objectOutputStream.writeObject(recordFromClient);
}
}
}
клиент:
package net.bounceme.dur.driver;
import java.net.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class Client {
private List<MyRecord> iterate() {
MyRecord myRecord = null;
List<MyRecord> records = new ArrayList<>();
for (int i = 0; i < 9; i ) {
myRecord = new MyRecord(i, "foo");
records.add(myRecord);
}
return records;
}
public void simple(String server, int portNumber) throws IOException, ClassNotFoundException {
Socket s = new Socket(server, portNumber);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
List<MyRecord> records = iterate();
for (MyRecord record : records) {
oos.writeObject(record);
}
oos.flush();
Object received = ois.readObject();
System.out.println(received);
oos.close();
ois.close();
}
public static void main(String args[]) throws IOException, ClassNotFoundException {
Properties props = PropertiesReader.getProps();
int portNumber = Integer.parseInt(props.getProperty("port"));
String server = (props.getProperty("server"));
new Client().simple(server, portNumber);
}
}
вывод сервера:
thufir@dur:~$
thufir@dur:~$ java -jar NetBeansProjects/Server/dist/Server.jar
Exception in thread "main" java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1876)
at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1785)
at java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1285)
at java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1230)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1426)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177)
at java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1576)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:350)
at net.bounceme.dur.driver.Server.readRecord(Server.java:32)
at net.bounceme.dur.driver.Server.main(Server.java:16)
thufir@dur:~$
вывод клиента:
thufir@dur:~$
thufir@dur:~$ java -jar NetBeansProjects/Client/dist/Client.jar
value=0, id='foo
thufir@dur:~$
Ответ №1:
Хорошо, в чем ваша проблема, ваш сервер был создан для чтения и обработки только одного объекта за раз. Итак, когда ваш клиент пытается отправить все эти объекты MyRecord, сервер считывает один, а затем пытается отправить его обратно вам, проблема в том, что вы все еще пытаетесь отправить другие объекты MyRecord, в то время как сервер пытается отправить вам ПЕРВЫЙ объект MyRecord. Соединения клиент / сервер похожи на игру в теннис. Один игрок должен подать мяч другому игроку, а другой должен затем отбить мяч обратно. Вы не можете оба ударить по мячу, ни один из вас не получает.
Итак, в,
for (MyRecord record : records) {
oos.writeObject(record);
}
oos.flush();
Object received = ois.readObject();
System.out.println(received);
вы должны поместить
oos.flush();
Object received = ois.readObject();
System.out.println(received);
таким образом, внутри for()
цикла каждый MyRecord
объект отправляется на сервер, считывается сервером, отправляется обратно клиенту сервером и считывается клиентом.
Конечный результат:
for (MyRecord record : records) {
oos.writeObject(record);
oos.flush();
Object received = ois.readObject();
System.out.println(received);
}
Комментарии:
1. при размышлении по одному объекту за раз все в порядке. Я просто хочу регистрировать объекты, которые сервер получает на этом этапе. Я обновил свой ответ.
Ответ №2:
Посмотрите изменения (я отредактировал некоторый код для запуска на моем компьютере, поэтому внесите соответствующие изменения)
import java.net.*;
import java.io.*;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.ArrayList;
import java.util.List;
class MyRecord implements java.io.Serializable
{
int x;
String y;
MyRecord(int a,String b)
{
x=a;
y=b;
}
}
class Server {
private static final Logger log = Logger.getLogger(Server.class.getName());
//private final RecordQueue recordsQueue = new RecordQueue();
public static void main(String[] args) throws IOException {
//Properties props = PropertiesReader.getProps();
//int portNumber = Integer.parseInt(props.getProperty("port"));
new Server().readRecord(2*1000);
}
public void readRecord(int portNumber) throws IOException {
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket socket = serverSocket.accept();
ObjectOutputStream objectOutputStream = null;
MyRecord recordFromClient = null;
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
while (true) {
try {
recordFromClient = (MyRecord) objectInputStream.readObject();
if(recordFromClient.x==-1) {break;}
} catch (ClassNotFoundException e) {
System.out.println(e);
}
objectOutputStream.writeObject(recordFromClient);
objectOutputStream.flush();
}
}
}
class Client {
private List<MyRecord> iterate() {
MyRecord myRecord = null;
List<MyRecord> records = new ArrayList<>();
for (int i = 0; i < 9; i ) {
myRecord = new MyRecord(i, "foo");
records.add(myRecord);
}
return records;
}
public void simple(String server, int portNumber) throws IOException, ClassNotFoundException {
Socket s = new Socket(server, portNumber);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
List<MyRecord> records = iterate();
for (MyRecord record : records) {
oos.writeObject(record);
oos.flush();
Object received = ois.readObject();
System.out.println(received);
}
MyRecord record= new MyRecord(-1,"end");
oos.writeObject(record);
oos.flush();
oos.close();
ois.close();
}
public static void main(String args[]) throws IOException, ClassNotFoundException {
//Properties props = PropertiesReader.getProps();
//int portNumber = Integer.parseInt(props.getProperty("port"));
String server = "localhost";
new Client().simple(server, 2000);
}
}
Комментарии:
1. почему вы используете
break
? Я немного обновил свой ответ, но все еще не могу зарегистрировать объект, который получает сервер.2. прерывание, потому что, когда клиент завершает отправку записей, сервер продолжает чтение, ожидая (не зная, что клиент отправил все записи, которые ему нужны) больше записей, поэтому, если вы прокомментируете это утверждение, вы получите исключение EOFException. это было сделано, чтобы сигнализировать о том, что клиент закончил отправку объектов
Ответ №3:
Это работает в определенной степени:
package net.bounceme.dur.driver;
//import stuff
public class Server {
private static final Logger log = Logger.getLogger(Server.class.getName());
private final RecordQueue recordsQueue = new RecordQueue();
public static void main(String[] args) {
Properties props = PropertiesReader.getProps();
int portNumber = Integer.parseInt(props.getProperty("port"));
while (true) {
try {
new Server().inOut(portNumber);
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(Server.class.getName()).log(Level.FINE, null, ex);
}
}
}
private List<MyRecord> dummyRecords() {
MyRecord record = null;
List<MyRecord> records = new ArrayList<>();
for (int i = 0; i < 9; i ) {
record = new MyRecord(i, "foo");
records.add(record);
log.info(record.toString());
}
return records;
}
public void inOut(int portNumber) throws IOException, ClassNotFoundException {
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket socket = serverSocket.accept();
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
log.info("...connected...waiting for data...");
MyRecord recordFromClient = (MyRecord) objectInputStream.readObject();
objectOutputStream.writeObject(recordFromClient);
objectOutputStream.flush();
objectInputStream.close();
objectOutputStream.close();
log.info(recordFromClient.toString());//never logs
System.out.println("never gets here");
}
}
за исключением того, что он никогда не регистрирует recordFromClient
, что отчасти важно. С положительной стороны, это не приводит к сбою.