Was ich zu erreichen versuche:
Ich versuche, eine sehr einfache Kamera-Überwachungssystem zu machen. In diesem Fall ist die Kamera der Server und es wird eine Client-Anwendung geben, um den Video-Feed am anderen Ende zu sehen.Socket-Programmierung: Der Eingangsstrom wird ohne Ausnahme beschädigt
Der Einfachheit halber werde ich die Kamera emulieren, indem die Bilder aus einer gespeicherten Videodatei aufnehmen, und Senden dieser einen Rahmen, die durch eine über Sockets an alle angeschlossenen Clients (Ja, die Kamera kann mehr als ein Client behandeln). Auf der Client-Seite werde ich die Frames erhalten und dann werde ich sie nacheinander in einem jPanel anzeigen, um den Effekt eines Video-Playings zu erzeugen.
Ich habe schon alles gemacht, aber es funktioniert nur für ein paar Frames, dann hört es plötzlich ohne Ausnahme auf.
die Server-Seite:
Dies ist die wichtigste Funktion in der Kamera Klasse:
public static void main(String[] args) throws InterruptedException, IOException, RemoteException, AlreadyBoundException {
ServerSocket ssock = new ServerSocket(1234);
System.out.println("Listening");
Camera.getInstance().startCamera(); // Starts reading the frames from the video file
while (true) {
Socket sock = ssock.accept();
System.out.println("Connected");
ClientConnection con = new ClientConnection(sock); // Creates a new connection
// Runs the connection on it's own thread
Thread conThread = new Thread(con);
conThread.start();
// Keeps a reference to the connection so it can be used later to send frames
Camera.getInstance().connections.add(con);
}
}
Snippets aus der Clientconnection Klasse:
Der Konstruktor:
public ClientConnection(Socket csocket) throws IOException {
this.csocket = csocket;
outStream = new PrintStream(csocket.getOutputStream());
objectOutStream = new ObjectOutputStream(csocket.getOutputStream());
}
Die Clientconnection Klasse implementiert die Schnittstelle runnable so dass es auf einem separaten Thread arbeiten kann. Die run-Methode ist verantwortlich für den Empfang vordefinierter Nachrichten (ex. "SET_MOVIE") vom Client und einige Aktionen entsprechend. Diese Aktionen und was sie tun sind für die Frage irrelevant, so dass wir sie ignorieren können. Hier ist die run-Methode:
@Override
public void run() {
try {
inStream = new Scanner(csocket.getInputStream());
String msg;
while (inStream.hasNext()) {
msg = inStream.nextLine();
if (msg.equals("SET_MOVIE")) {
setMovie();
} else if (msg.equals("SET_IDLE")) {
setIdle();
} else if (msg.equals("FORCE_STATE_ON")) {
forceStateOn();
} else if (msg.equals("FORCE_STATE_OFF")) {
forceStateOff();
} else if (msg.equals("DISCONNECT")) {
// TO-DO
}
}
} catch (IOException ex) {
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
Dies ist die sendFrame Methode in der Clientconnection Klasse. Es wird jedes Mal aufgerufen, wenn ein neuer Frame verfügbar und bereit zum Senden ist.
// SEND_FRAME here works as an indicator to the client so that it can expect
// the image and start reading it
public void sendFrame(Frame _frame) throws IOException {
outStream.println("SEND_FRAME"); //tells the client there is a new frame
outStream.println(_frame.getCaptureTime()); //sends the time in which the frame was captured
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(_frame.getFrame(), "jpg", byteArrayOutputStream);
byte[] size = ByteBuffer.allocate(4).putInt(byteArrayOutputStream.size()).array();
outStream.write(size);
outStream.write(byteArrayOutputStream.toByteArray());
outStream.flush();
}
der Client-Seite:
Dies ist die wichtigste Methode ist, schafft es einfach eine neue CameraConnection und führen Sie es auf seinen eigenen Thread.
public static void main(String[] args) throws InterruptedException, IOException {
Thread client = new Thread(new CameraConnection("Cam_1", 1234));
client.start();
}
Dies ist der CameraConnection Konstruktor:
public CameraConnection(String name, int port) throws IOException {
this.name = name;
clientSocket = new Socket("localhost", port);
// This scanner will be used to read messages sent from the server
// such as "SEND_FRAME"
inStream_scanner = new Scanner(clientSocket.getInputStream());
// This inputStream will be used to read the bufferedImage in a array of bits
inStream = clientSocket.getInputStream();
// This is the outStream used to send messaages to the server
outStream = new PrintStream(clientSocket.getOutputStream());
}
Dies ist das Run-Methode innerhalb des CameraConnection:
@Override
public void run() {
String msg;
while (inStream_scanner.hasNext()) {
// Stores the incoming message and prints it
msg = inStream_scanner.nextLine();
System.out.println(msg);
// Irrelevant
if (msg.equals("NOTIFY_MOTION")) {
onMotion();
}
// Here is where the image gets read
else if (msg.equals("SEND_FRAME")) {
Frame f = new Frame();
long capturedTime = inStream_scanner.nextLong();
try {
byte[] sizeAr = new byte[4];
inStream.read(sizeAr);
int size = ByteBuffer.wrap(sizeAr).asIntBuffer().get();
byte[] imageAr = new byte[size];
inStream.read(imageAr);
BufferedImage image = null;
image = ImageIO.read(new ByteArrayInputStream(imageAr));
long receivedTime = System.currentTimeMillis();
// Prints out the image dimension and the time in which it was received
System.out.println("Received " + image.getHeight() + "x" + image.getWidth() + ": " + receivedTime);
f.setCaptureTime(capturedTime);
f.setFrame(image);
f.setRecievedTime(receivedTime);
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
}
Der Ausgang:
Wie bereits erwähnt, arbeitet es für ein paar Frames fein dann hält er ohne Ausnahme, auch der Scanner aus der input beginnt das Lesen und Drucken seltsame Symbole auf die Konsole als ob sie beschädigt ist. Es druckt diese seltsamen Symbole so lange, wie der Server die Frames weiter sendet. Hier ist ein Bild mit dem Ausgang: screenshot from the output
@HovercraftFullOfEels Hier gibt es keinen [tag: swing] -Code. – EJP
Ja, ich habe den Swing-Code nicht angegeben, weil ich das Problem auf der Konsole reproduzieren konnte. –