2016-04-11 4 views
0

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

+0

@HovercraftFullOfEels Hier gibt es keinen [tag: swing] -Code. – EJP

+0

Ja, ich habe den Swing-Code nicht angegeben, weil ich das Problem auf der Konsole reproduzieren konnte. –

Antwort

1
  • Sie können nicht zwei Arten von Strom oder Leser oder Schreiber auf dem gleichen Sockel mischen. Puffern wird dich völlig verderben. Sie müssen die Objektströme für alles verwenden.
  • Sie können nicht davon ausgehen, dass read() den Puffer füllt.
  • Zum Lesen einer 4-Byte-Ganzzahl sollten Sie readInt() (und writeInt() zum Schreiben) verwenden, nicht hausgemachten Code.
  • Zum Lesen des Bildkörpers sollten Sie readFully() verwenden.
  • Ich sehe keine Notwendigkeit für Objektströme hier: Sie sollten DataInputStream und DataOutputStream verwenden.
+0

Nur um sicherzugehen, dass ich richtig verstehe, sagst du, dass ein Sockel entweder zum Lesen oder Schreiben verwendet wird und nicht beides, oder? Was ist, wenn ich Daten senden und empfangen möchte? Soll ich 2 Socket-Anschlüsse machen? –

+0

okay, egal, ich habe das Problem gelöst, indem ich Objektströme nur für beide Seiten verwendet habe. Ich danke dir sehr. –

Verwandte Themen