JavaFx学习--chapter02(网络对话)

chapter02(网络对话)

简单网络对话程序

设计任务:客户端向服务器发送字符串,并能读取服务器返回的字符串。

知识点:TCP套接字技术,C/S软件架构程序设计

重点理解:Java客户套接字类Socket和服务器套接字类ServerSocket,以及配套使用流的读/写类BufferedReader/PrintWriter

C/S软件架构程序设计技术中,实现网络通信的两个应用进程,一个叫做服务进程,另一个叫做客户进程,如图所示。服务进程首先被动打开一个 监听端口,如8008,客户进程主动访问这个端口,完成对话聊天前的TCP三 次握手连接。

在这里插入图片描述

Java 的 TCP/IP 套接字编程将底层的细节进行了封装,其编程模型如图

在这里插入图片描述

socket套接字类

Java TCP/IP 编程模型中,有两个套接字类:服务进程中的是 ServerSocket 类客户进程中的是Socket类。 服务进程首先开启一个或多个监听端口,客户进程向服务进程发起TCP三次握手连接。

TCP 连接成功后,逻辑上可理解为通信进程的双方具有两个流(输出流和输入流)。逻辑上可将两个流理解为两个通信管道的全双工通信模式,一个用于向对方发送数据,另一个用于接收对方的数据。

成员方法

套接字类有两个基本的方法可以获得两个通信管道:

  1. socket.getInputStream() 方法可获得输入字节流的入口;
  2. socket.getOutputStream() 方法可获得输出字节流的出口;
监听套接字和通信套接字

在网络编程中,监听套接字(Listening Socket)和通信套接字(Communication Socket)是两个重要的概念,通常用于实现客户端和服务器之间的通信。以下是对这两个概念的详细解释:

1. 监听套接字(Listening Socket)
  • 定义:监听套接字是服务器端创建的套接字,用于监听来自客户端的连接请求。它不直接用于数据传输,而是用于接受连接。
  • 创建:在服务器端,首先需要创建一个套接字并将其绑定到一个特定的地址和端口,然后调用 listen() 方法使其进入监听状态。
  • 功能
    • 等待客户端的连接请求。
    • 一旦有客户端请求连接,服务器会接受这个连接并创建一个新的通信套接字。

示例代码(C++):

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>int main() {int server_fd = socket(AF_INET, SOCK_STREAM, 0); // 创建监听套接字if (server_fd == 0) {std::cerr << "Socket creation failed" << std::endl;return -1;}struct sockaddr_in address;address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY; // 监听所有可用的接口address.sin_port = htons(8080); // 端口号bind(server_fd, (struct sockaddr *)&address, sizeof(address)); // 绑定地址和端口listen(server_fd, 3); // 开始监听,最大连接数为3std::cout << "Listening on port 8080..." << std::endl;return 0;
}
2. 通信套接字(Communication Socket)
  • 定义:通信套接字是服务器在接受客户端连接请求后创建的套接字,用于与特定客户端进行数据传输。
  • 创建:当监听套接字接受到连接请求后,服务器会调用 accept() 方法,返回一个新的套接字(通信套接字),用于与该客户端进行通信。
  • 功能
    • 进行数据的发送和接收。
    • 每个连接的客户端都有一个独立的通信套接字。
  • 示例代码(C++):
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>int main() {int server_fd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in address;int addrlen = sizeof(address);// 省略监听套接字的创建和绑定代码...listen(server_fd, 3);std::cout << "Listening on port 8080..." << std::endl;int client_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen); // 接受连接if (client_socket < 0) {std::cerr << "Accept failed" << std::endl;return -1;}const char *message = "Hello from server";send(client_socket, message, strlen(message), 0); // 发送数据std::cout << "Message sent to client" << std::endl;close(client_socket); // 关闭通信套接字close(server_fd); // 关闭监听套接字return 0;
}
总结
  • 监听套接字:用于等待和接受客户端的连接请求。
  • 通信套接字:用于与已连接的客户端进行数据传输。

这种设计使得服务器能够同时处理多个客户端连接,因为每个连接都有自己的通信套接字,而监听套接字则保持在监听状态,等待新的连接请求。如果你有更多问题或需要进一步的帮助,请告诉我!

模拟Button的点击事件

在JavaFX中,模拟按钮(Button)的点击可以通过直接调用按钮的fire()方法来实现,但请注意,Button类本身并没有直接提供fire()方法。不过,Button类继承自javafx.scene.control.Control,而Control类有一个受保护的fire()方法,但这个方法通常不是用来直接模拟用户点击事件的。

更好的方法是定义一个可以在代码中调用的方法,该方法包含你想要在按钮点击时执行的代码。然后,你可以在按钮的事件监听器中调用这个方法,也可以直接从代码的其他部分调用它。

import javafx.application.Application;  
import javafx.event.ActionEvent;  
import javafx.event.EventHandler;  
import javafx.scene.Scene;  
import javafx.scene.control.Button;  
import javafx.scene.layout.StackPane;  
import javafx.stage.Stage;  public class ButtonClickSimulationExample extends Application {  @Override  public void start(Stage primaryStage) {  Button btn = new Button();  btn.setText("Click Me!");  // 定义点击时执行的方法  EventHandler<ActionEvent> onButtonClick = event -> {  System.out.println("Button clicked!");  // 这里可以放置更多的代码  };  // 将事件监听器绑定到按钮  btn.setOnAction(onButtonClick);  // 直接从代码中“模拟”按钮点击  // 注意:这不是真正的模拟点击,而是直接调用了点击时要执行的代码  onButtonClick.handle(new ActionEvent());  StackPane root = new StackPane();  root.getChildren().add(btn);  Scene scene = new Scene(root, 300, 250);  primaryStage.setTitle("Button Click Simulation Example");  primaryStage.setScene(scene);  primaryStage.show();  }  public static void main(String[] args) {  launch(args);  }  
}

可以通过设置button的disable属性来控制是否能点击按钮

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;public class DisableButtonExample extends Application {@Overridepublic void start(Stage primaryStage) {Button btn = new Button("点击我");// 按钮点击事件btn.setOnAction(event -> {btn.setDisable(true);btn.setText("按钮已禁用");// 假设这里有一个异步操作,完成后重新启用按钮new Thread(() -> {try {Thread.sleep(2000); // 模拟异步操作} catch (InterruptedException e) {e.printStackTrace();}// 重新启用按钮btn.setDisable(false);btn.setText("点击我");}).start();});StackPane root = new StackPane();root.getChildren().add(btn);Scene scene = new Scene(root, 300, 250);primaryStage.setTitle("JavaFX Disable Button Example");primaryStage.setScene(scene);primaryStage.show();}public static void main(String[] args) {launch(args);}
}

最终代码

TCPServer.java
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;public class TCPServer {private final int port; // 服务器监听端口号private final ServerSocket serverSocket; //定义服务器套接字public TCPServer() throws IOException {Scanner scanner = new Scanner(System.in); // 创建一个Scanner对象来读取标准输入System.out.println("请输入服务器监听的端口号:");if (scanner.hasNextInt()) { // 检查是否有下一个输入项并且是一个整数port = scanner.nextInt(); // 读取整数并赋值给port} else {System.out.println("输入错误,请输入一个有效的整数端口号。");// 这里可以根据需要处理错误情况,比如使用默认值或者退出程序port = 8080; // 例如,使用8080作为默认端口号}scanner.close(); // 关闭scanner对象serverSocket = new ServerSocket(port);System.out.println("服务器启动监听在 " + port + " 端口");}private PrintWriter getWriter(Socket socket) throws IOException {//获得输出流缓冲区的地址OutputStream socketOut = socket.getOutputStream();//网络流写出需要使用flush,这里在PrintWriter构造方法中直接设置为自动flushreturn new PrintWriter(new OutputStreamWriter(socketOut, StandardCharsets.UTF_8), true);}private BufferedReader getReader(Socket socket) throws IOException {//获得输入流缓冲区的地址InputStream socketIn = socket.getInputStream();return new BufferedReader(new InputStreamReader(socketIn, StandardCharsets.UTF_8));}//单客户版本,即每一次只能与一个客户建立通信连接public void Service() {while (true) {Socket socket = null;try {//此处程序阻塞等待,监听并等待客户发起连接,有连接请求就生成一个套接字。socket = serverSocket.accept();//本地服务器控制台显示客户端连接的用户信息System.out.println("New connection accepted: " + socket.getInetAddress().getHostAddress());BufferedReader br = getReader(socket);//定义字符串输入流PrintWriter pw = getWriter(socket);//定义字符串输出流//客户端正常连接成功,则发送服务器的欢迎信息,然后等待客户发送信息pw.println("From 服务器:欢迎使用本服务!");String msg = null;//此处程序阻塞,每次从输入流中读入一行字符串while ((msg = br.readLine()) != null) {//如果客户发送的消息为"bye",就结束通信if (msg.equals("bye")) {//向输出流中输出一行字符串,远程客户端可以读取该字符串pw.println("From服务器:服务器断开连接,结束服务!");System.out.println("客户端离开");break; //结束循环}//向输出流中输出一行字符串,远程客户端可以读取该字符串pw.println("From服务器:" + msg);}} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}finally {try {if(socket != null)socket.close(); //关闭socket连接及相关的输入输出流} catch (IOException e) {e.printStackTrace();}}}}public static void main(String[] args) throws IOException {TCPServer server = new TCPServer();System.out.println("服务器将监听端口号: " + server.port);server.Service();}
}
TCPClient.java
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;public class TCPClient {private final Socket socket; // 定义套接字private final PrintWriter pw; // 定义字符输出流private final BufferedReader br; // 定义字符输入流public TCPClient(String ip, String port) throws IOException {// 主动向服务器发起连接,实现TCP的三次握手过程// 如果不成功,则抛出错误信息,其错误信息交由调用者处理socket = new Socket(ip, Integer.parseInt(port));// 得到网络输出字节流地址,并封装成网络输出字符流// 设置最后一个参数为true,表示自动flush数据OutputStream socketOut = socket.getOutputStream();pw = new PrintWriter(new OutputStreamWriter(socketOut, StandardCharsets.UTF_8), true);// 得到网络输入字节流地址,并封装成网络输入字符流InputStream socketIn = socket.getInputStream();br = new BufferedReader(new InputStreamReader(socketIn, StandardCharsets.UTF_8));}public void send(String msg) {// 输出字符流,由Socket调用系统底层函数,经网卡发送字节流pw.println(msg);}public String receive() {String msg = null;try {// 从网络输入字符流中读信息,每次只能接收一行信息// 如果不够一行(无行结束符),则该语句阻塞等待msg = br.readLine();} catch (IOException e) {e.printStackTrace();}return msg;}// 实现close方法以关闭socket连接及相关的输入输出流public void close() {try {if (pw != null) {pw.close(); // 关闭PrintWriter会先flush再关闭底层流}if (br != null) {br.close(); // 关闭BufferedReader}if (socket != null) {socket.close(); // 关闭Socket连接}} catch (IOException e) {e.printStackTrace();}}
}
SimpleFx(窗口)
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.*;
import javafx.stage.Stage;import java.io.IOException;public class SimpleFx extends Application {private TCPClient tcpClient;private final Button btnCon = new Button("连接");private final Button btnExit = new Button("退出");private final Button btnSend = new Button("发送");private final TextField IpAdd_input = new TextField();private final TextField Port_input = new TextField();private final TextArea OutputArea = new TextArea();private final TextField InputField = new TextField();public void start(Stage primaryStage) {BorderPane mainPane = new BorderPane();VBox mainVBox = new VBox();HBox hBox = new HBox();hBox.setSpacing(10);//各控件之间的间隔//HBox面板中的内容距离四周的留空区域hBox.setPadding(new Insets(20, 20, 10, 20));hBox.getChildren().addAll(new Label("IP地址: "), IpAdd_input, new Label("端口: "), Port_input, btnCon);hBox.setAlignment(Pos.TOP_CENTER);//内容显示区域VBox vBox = new VBox();vBox.setSpacing(10);//各控件之间的间隔//VBox面板中的内容距离四周的留空区域vBox.setPadding(new Insets(10, 20, 10, 20));vBox.getChildren().addAll(new Label("信息显示区:"), OutputArea, new Label("信息输入区"), InputField);//设置显示信息区的文本区域可以纵向自动扩充范围VBox.setVgrow(OutputArea, Priority.ALWAYS);// 设置文本只读和自动换行OutputArea.setEditable(false);OutputArea.setStyle("-fx-wrap-text: true; /* 实际上是默认的 */ -fx-font-size: 14px;");InputField.setOnKeyPressed(event -> {if (event.getCode() == KeyCode.ENTER) {btnSend.fire();}});//底部按钮区域HBox hBox2 = new HBox();hBox2.setSpacing(10);hBox2.setPadding(new Insets(10, 20, 10, 20));// 设置按钮的交互效果btnCon.setOnAction(event -> {String ip = IpAdd_input.getText().trim();String port = Port_input.getText().trim();try {//tcpClient不是局部变量,是本程序定义的一个TCPClient类型的成员变量tcpClient = new TCPClient(ip, port);//成功连接服务器,接收服务器发来的第一条欢迎信息String firstMsg = tcpClient.receive();OutputArea.appendText(firstMsg + "\n");} catch (Exception e) {OutputArea.appendText("服务器连接失败!" + e.getMessage() + "\n");}});btnExit.setOnAction(event -> {if (tcpClient != null){//向服务器发送关闭连接的约定信息tcpClient.send("bye");tcpClient.close();}System.exit(0);});btnSend.setOnAction(event -> {String sendMsg = InputField.getText();tcpClient.send(sendMsg);//向服务器发送一串字符InputField.clear();OutputArea.appendText("客户端发送:" + sendMsg + "\n");String receiveMsg = tcpClient.receive();//从服务器接收一行字符OutputArea.appendText(receiveMsg + "\n");});hBox2.setAlignment(Pos.CENTER_RIGHT);hBox2.getChildren().addAll(btnSend, btnExit);mainVBox.getChildren().addAll(hBox, vBox, hBox2);mainPane.setCenter(mainVBox);VBox.setVgrow(vBox, Priority.ALWAYS);Scene scene = new Scene(mainPane, 700, 400);primaryStage.setScene(scene);primaryStage.show();}public static void main(String[] args) {launch(args);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/57157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蜜罐技术的出现究竟影响了什么

自网络诞生以来&#xff0c;攻击威胁事件层出不穷&#xff0c;网络攻防对抗已成为信息时代背景下的无硝烟战争。然而&#xff0c;传统的网络防御技术如防火墙、入侵检测技术等都是一种敌暗我明的被动防御&#xff0c;难以有效应对攻击者随时随地发起的无处不在的攻击和威胁。蜜…

linux线程 | 同步与互斥 | 互斥(下)

前言&#xff1a;本篇文章主要讲述linux线程的互斥的知识。 讲解流程为先讲解锁的工作原理&#xff0c; 再自己封装一下锁并且使用一下。 做完这些就要输出一堆理论性的东西&#xff0c; 但博主会总结两条结论&#xff01;&#xff01;最后就是讲一下死锁。 那么&#xff0c; 废…

什么是 Idempotence 以及它在哪里使用?

大家好&#xff0c;我是锋哥。今天分享关于【什么是 Idempotence 以及它在哪里使用&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; 什么是 Idempotence 以及它在哪里使用&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Idempotence&am…

【C++STL】list的基本介绍与使用方式

✨ Blog’s 主页: 白乐天_ξ( ✿&#xff1e;◡❛) &#x1f308; 个人Motto&#xff1a;他强任他强&#xff0c;清风拂山冈&#xff01; &#x1f525; 所属专栏&#xff1a;C深入学习笔记 &#x1f4ab; 欢迎来到我的学习笔记&#xff01; 一、list的介绍 文档内容以及大致翻…

ESP32-IDF 非易失存储 NVS

目录 零、前言一、基本介绍1、配置结构体1.1 nvs_entry_info_t 2、常用 API2.1 nvs_flash_init2.2 nvs_flash_init_partition2.3 nvs_flash_init_partition_ptr2.4 nvs_flash_erase2.5 nvs_flash_erase_partition2.6 nvs_flash_erase_partition_ptr2.7 nvs_flash_generate_keys…

element plus中menu菜单技巧

我在使用element plus的menu&#xff08;侧边栏&#xff09;组件的过程中遇到了一些问题&#xff0c;就是menu编写样式和路由跳转&#xff0c;下面给大家分享以下&#xff0c;我是怎么解决的。 1.页面效果 我要实现的网站布局是这样的&#xff1a; 侧边栏折叠以后的效果&#…

python爬虫快速入门之---Scrapy 从入门到包吃包住

python爬虫快速入门之—Scrapy 从入门到包吃包住 文章目录 python爬虫快速入门之---Scrapy 从入门到包吃包住一、scrapy简介1.1、scrapy是什么?1.2、Scrapy 的特点1.3、Scrapy 的主要组件1.4、Scrapy 工作流程1.5、scrapy的安装 二、scrapy项目快速入门2.1、scrapy项目快速创建…

详解equals底层原理

equals 方法是 Java 中用于比较两个对象是否“相等”的方法。在 Java 中&#xff0c;每个类都继承自 java.lang.Object 类&#xff0c;而 equals 方法正是定义在 Object 类中的一个方法。默认情况下&#xff0c;Object 类的 equals 方法比较的是两个对象的内存地址&#xff08;…

SQL 多表联查

SQL JOIN (w3school.com.cn) SQL join用于根据两个或多个表中的列之间的关系&#xff0c;从这些表中查询数据。 之前跟着老师学数据库的时候学过&#xff0c;最近又在比较频繁的使用&#xff0c;再复习一下。 Person表&#xff1a; Id_P &#xff1a;居民编号。主键 …

大数据开发基于Hadoop+springboot平台的岗位推荐系统

文章目录 前言项目介绍技术介绍功能介绍核心代码数据库参考 系统效果图文章目录 前言 文章底部名片&#xff0c;获取项目的完整演示视频&#xff0c;免费解答技术疑问 项目介绍 随着网络科学技术不断的发展和普及化&#xff0c;用户在寻找适合自己的信息管理系统时面临着越来…

成功解决pycharm软件中按住Ctrl+点击指定函数却不能跳转到对应库中的源代码

成功解决pycharm软件中按住Ctrl点击指定函数却不能跳转到对应库中的源代码 目录 解决问题 解决方法 解决问题 在pycharm软件中按住Ctrl点击指定函数却不能跳转到对应库中的源代码 解决方法

探索秘境:如何使用智能体插件打造专属的小众旅游助手『小众旅游探险家』

文章目录 摘要引言智能体介绍和亮点展示介绍亮点展示 已发布智能体运行效果智能体创意想法创意想法创意实现路径拆解 如何制作智能体可能会遇到的几个问题快速调优指南总结未来展望 摘要 本文将详细介绍如何使用智能体平台开发一款名为“小众旅游探险家”的旅游智能体。通过这…

个人健康系统|个人健康数据管理系统|基于小程序+java的个人健康数据管理系统设计与实现(源码+数据库+文档)

个人健康数据管理系统 目录 基于小程序java的个人健康数据管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师…

重构案例:将纯HTML/JS项目迁移到Webpack

我们已经了解了许多关于 Webpack 的知识&#xff0c;但要完全熟练掌握它并非易事。一个很好的学习方法是通过实际项目练习。当我们对 Webpack 的配置有了足够的理解后&#xff0c;就可以尝试重构一些项目。本次我选择了一个纯HTML/JS的PC项目进行重构&#xff0c;项目位于 GitH…

web3学习-区块链基础知识

1.1 区块链技术简史 block chain 点对点的分布式交易系统 比特币协议并不是图灵完备的。 以太坊协议加入了智能合约&#xff0c;智能合约是以太坊协议与比特币协议的最大区别&#xff08;图灵完备&#xff09; 1.2、区块链设计哲学 去中心化 由于没有中心化的数据库作为…

记录一个容易混淆的 Spring Boot 项目配置文件问题

记录一个容易混淆的 Spring Boot 项目配置文件问题 去年&#xff0c;我遇到了这样一个问题&#xff1a; 在这个例子中&#xff0c;由于密码 password 以 0 开头&#xff0c;当它被 Spring Boot 的 bean 读取时&#xff0c;前导的 0 被自动去掉了。这导致程序无法正确读取密码。…

网盘直链下载神器NDM

工具介绍 ​Neat Download Manager分享一款网盘不限速神器,安装步骤稍微有一点繁琐,但实际体验下载速度飞快,个人实际体验还是非常不错的 NDM是一款免费且强大的下载工具。可以帮助你下载各种文件&#xff0c;还能够在多任务下载中保持出色的速度及其稳定性 通过网盘分享的文…

【MySQL核心面试题】MySQL 核心 - Explain 执行计划详解!

欢迎关注公众号 【11来了】&#xff08;文章末尾即可扫码关注&#xff09; &#xff0c;持续 中间件源码、系统设计、面试进阶相关内容 在我后台回复 「资料」 可领取 编程高频电子书&#xff01; 在我后台回复「面试」可领取 30w 字的硬核面试笔记&#xff01; 感谢你的关注&…

MySQL【知识改变命运】10

联合查询 0.前言1.联合查询在MySQL里面的原理2.练习一个完整的联合查询2.1.构造练习案例数据2.2 案例&#xff1a;⼀个完整的联合查询的过程2.2.1. 确定参与查询的表&#xff0c;学⽣表和班级表2.2.2. 确定连接条件&#xff0c;student表中的class_id与class表中id列的值相等2.…

wordpress 子比主题美化 四宫格 多宫格 布局插件

wordpress 主题美化 四宫格 多宫格 布局插件&#xff08;只在子比主题上测试过&#xff0c;其它主题没测试&#xff09; A5资源网四宫格布局插件是一个功能丰富的WordPress插件,专为创建自适应的四宫格布局而设计。这个插件具有以下主要特点: 灵活的布局: 支持1到8个宫格的自定…