Java网络编程-简易qq实现

实现效果

Java网络编程-简易qq实现_第1张图片## 代码

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import java.net.*;
import java.io.*;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage){
        //端口定义
        int receive_port = 8002;
        int send_port = 8001;

        // 滚动显示消息的屏幕
        VBox topTop = new VBox();
        TextArea topDisplay = new TextArea();
        Text in = new Text("消息会话");
        topTop.getChildren().addAll(in, topDisplay);
        topDisplay.setEditable(false);  // 设置为不可编辑
        topDisplay.setStyle("-fx-border-color: gray; -fx-border-width: 3px");  // 设置边框颜色及宽度

        // 中间输入的地方
        HBox center = new HBox();
        TextArea cenText = new TextArea();
        Text out = new Text("消息发送");
        center.getChildren().addAll(out, cenText);
        cenText.setStyle("-fx-border-color: gray; -fx-border-width: 4px");

        // 最下方条件框
        Text ip = new Text("通信地址(ip):");
        TextField ipText = new TextField();
        Button clear = new Button("清屏");
        Button send = new Button("发送");
        HBox bar = new HBox();
        bar.getChildren().addAll(ip, ipText, clear, send);
        bar.setAlignment(Pos.CENTER);  // 底部布局居中
        bar.setSpacing(15);  // 底部节点之间的间隔

        // 最终展示
        BorderPane borderPane = new BorderPane();
        borderPane.setTop(topTop);
        borderPane.setCenter(center);
        borderPane.setBottom(bar);
        Scene scene = new Scene(borderPane, 500, 450);
        primaryStage.setTitle("ByackQQ");
        primaryStage.setScene(scene);
        primaryStage.show();

        // ************************服务器端线程运行*****************************
        class Server implements Runnable {
            private boolean flag = true;

            void setFlag(boolean temp) {
                this.flag = temp;
            }

            @Override
            public void run() {
                ServerSocket serverSocket = null;
                try {
                    serverSocket = new ServerSocket(receive_port);
                    while (this.flag) {
                        Socket server = serverSocket.accept();
                        DataInputStream in = new DataInputStream(server.getInputStream());
                        Thread.sleep(100);  // 等待发送消息先输出显示
                        topDisplay.appendText("$ " + server.getRemoteSocketAddress() + " 向 本机 发送消息:" + "\n");
                        topDisplay.appendText("       ---> " + in.readUTF() + "\n");
                        server.close();
                    }
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        // 运行服务器端线程
        Server server = new Server();
        Thread s = new Thread(server);
        s.start();

        // ********************************事件处理******************************

        // 输入回车触发发送
        cenText.setOnKeyReleased(e -> {
            if (e.getCode() == KeyCode.ENTER) {
                Send(send, ipText, cenText, topDisplay, send_port);
            }
        });

        // Clear点击清屏
        clear.setOnMouseClicked(e -> {
            topDisplay.setText("");
        });

        // 点击发送
        send.setOnMouseClicked(e -> {
            Send(send, ipText, cenText, topDisplay, send_port);
        });

        // 监听舞台关闭时关闭服务端线程
        primaryStage.setOnCloseRequest(e -> {
            server.setFlag(false);  // 更改线程标志位
            // 因为是这个线程是阻塞式的,所以主线程关闭后,我们再发送一个信息服务器线程
            // 使程序继续执行,标志位已经更改,可以达到正常退出服务线程的目的
            try {
                Socket client = new Socket(ipText.getText(), receive_port);
                OutputStream outToServer = client.getOutputStream();
                DataOutputStream OutText = new DataOutputStream(outToServer);
                OutText.writeUTF("");
                client.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        });
    }

    // 发送
    private static void Send(Button send, TextField ipText, TextArea cenText, TextArea topDisplay, int send_port) {
        try {
            Socket client = new Socket(ipText.getText(), send_port);
            OutputStream outToServer = client.getOutputStream();
            DataOutputStream OutText = new DataOutputStream(outToServer);
            OutText.writeUTF(cenText.getText());
            topDisplay.appendText("$ 本机 向 " + ipText.getText() + " 发送消息:" + "\n");
            topDisplay.appendText("       ---> " + cenText.getText() + "\n");
            cenText.setText("");
            client.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

后记

整体框架是现将客户端的程序写好,这个程序作为客户端也作为服务端,代码中有使用类中类来说明服务端的运行,通过另一个线程来运行服务端的程序,服务器的端的是程序属于阻塞型的,在关闭客户端后,服务端的这个线程会接着运行,为了解决这个问题,我监听鼠标舞台关闭事件,在关闭运行窗口时,更改服务端线程运行的循环标志位,再发送一个消息给到服务器端,服务器线程收到消息,不再阻塞,向下执行,执行到最后,不满足条件,不再继续循环,正常退出服务器线程。

你可能感兴趣的:(Java)