问题
I am trying to send the live screen of the client to the server. It's a one-way communication till now. They seem to connect, but somehow the whole data might not be sent. I can't understand where the problem lies. Only a still image is shared in spite of a continuous stream of images. Will I have to use another AnimationTimer in the server-class and how? If not, how can I achieve a live sharing of the screen? My code is as follows:
Image info class shared by both server & client:
package sample;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class imageData implements Serializable {
private transient Image wi;
private String msg;
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
wi = SwingFXUtils.toFXImage(ImageIO.read(s), null);
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
ImageIO.write(SwingFXUtils.fromFXImage(wi, null), "png", s);
}
public void setWi(WritableImage wi) { this.wi = wi; }
public Image getWi() { return wi; }
}
Server main class:
package sample;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("sample.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root));
primaryStage.show();
Controller controller = loader.getController();
controller.setM(this);
try{
ServerSocket ss = new ServerSocket(8888);
Socket s = ss.accept();
new conn(s, controller);
}catch(Exception e){
System.out.println(e);
}
}
public void setIV(WritableImage wi) { }
public static void main(String[] args) {
launch(args);
}
}
Server conn class:
package sample;
import javafx.scene.control.Control;
import javafx.scene.image.WritableImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class conn {
private Socket s;
private ObjectInputStream is;
private Main m;
private Controller controller;
public conn(Socket s, Controller controller) throws Exception {
this.s = s;
ObjectInputStream is = new ObjectInputStream(s.getInputStream());
this.controller = controller;
connTh cth = new connTh(s, is, controller);
cth.start();
}
public void setMain(Main m) { this.m = m; }
public void setController(Controller controller) { this.controller = controller; }
public class connTh extends Thread{
Socket s;
private ObjectInputStream is;
private Controller controller;
public connTh(Socket s, ObjectInputStream is, Controller controller) throws Exception{
this.s = s;
this.is = is;
this.controller = controller;
}
@Override
public void run(){
while(true){
try{
imageData id = (imageData)is.readObject();
Image newImage = id.getWi();
controller.setIv(newImage);
//WritableImage oldImage = (WritableImage) controller.getIv();
}catch(Exception e){
System.out.println(e);
}
}
}
}
}
Server controller:
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import java.awt.*;
public class Controller {
private Main m;
private conn c;
@FXML private ImageView iv;
@FXML private Label lbl;
public void setIv(Image wi) { iv.setImage(wi); }
public Image getIv() { return iv.getImage(); }
public void setM(Main m) { this.m = m; }
public void setC(conn c) { this.c = c; }
}
Server fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml" xmlns="http://javafx.com/javafx" fx:controller="sample.Controller">
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
</rowConstraints>
<children>
<AnchorPane prefHeight="500.0" prefWidth="500.0">
<children>
<ImageView fx:id="iv" fitHeight="347.0" fitWidth="436.0" layoutX="32.0" layoutY="47.0" pickOnBounds="true" preserveRatio="true" />
<Label fx:id="lbl" layoutX="189.0" layoutY="7.0" prefHeight="30.0" prefWidth="72.0" text="VIEW" />
<Separator layoutX="113.0" layoutY="35.0" prefWidth="200.0" />
</children>
</AnchorPane>
</children>
</GridPane>
Client main class:
package sample;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.robot.Robot;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import javax.swing.text.Position;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
ImageView iv = new ImageView();
iv.setFitWidth(500);
iv.setFitHeight(400);
Text t = new Text("Screen Sharing");
t.setTextAlignment(TextAlignment.CENTER);
t.setFill(Color.FIREBRICK);
t.setStyle("-fx-font: 18 arial;");
Button b = new Button("Exit");
b.setAlignment(Pos.BASELINE_CENTER);
b.setOnAction(event -> {
Platform.exit();
});
VBox v = new VBox(10);
v.getChildren().addAll(t,iv,b);
primaryStage.setScene(new Scene(v, 500, 500));
primaryStage.show();
try{
Socket s = new Socket("localhost", 8888);
ObjectOutputStream os = new ObjectOutputStream(s.getOutputStream());
new network(s, os);
}catch(Exception e){
System.out.println(e);
}
}
public static void main(String[] args) {
launch(args);
}
}
Client network class:
package sample;
import javafx.animation.AnimationTimer;
import javafx.geometry.Rectangle2D;
import javafx.scene.image.WritableImage;
import javafx.scene.robot.Robot;
import javafx.stage.Screen;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
public class network {
private Socket s;
private ObjectOutputStream os;
public network(Socket s, ObjectOutputStream os){
this.s = s;
this.os = os;
new AnimationTimer() {
int c = 1;
final Robot robot = new Robot();
final Rectangle2D bounds = Screen.getPrimary().getBounds();
WritableImage i =robot.getScreenCapture(wi,bounds);
imageData id = new imageData();
@Override
public void handle(long now) {
if(c == 1){
try{
c++;
id.setWi(i);
os.writeObject(id);
os.reset();
}catch(Exception e){
System.out.println(e);
}
}
else{
try{
WritableImage oldImage = (WritableImage)id.getWi();
WritableImage newImage = robot.getScreenCapture(oldImage,bounds);
if(oldImage != newImage){
id.setWi(newImage);
os.writeObject(id);
os.reset();
}
}catch(Exception e){
System.out.println(e);
}
}
}
}.start();
}
来源:https://stackoverflow.com/questions/62565698/sharing-screen-via-java-socket-programming