Java网络编程

目录

1.网络编程

2.Echo模型(服务器与客户端实现通信)

3.BIO处理模型(实现多用户访问同个服务器)

4.UDP程序


1.网络编程

有两种通信模型

C/S(Client/Server)基于客户端和服务器端,实现代码时候需要实现客户端与服务器端

B/S(Browser/Server)基于Http网页和服务器端,实现时候只需要实现服务器端即可


2.Echo模型(服务器与客户端实现通信)

所谓Echo模型就是指的是客户端发送消息到服务器端,服务器接收到消息然后将客户端接收到的信息进行回送到客户端。所以需要编写两个端口一个客户端,一个服务器端。java中可以使用Socket类实现用户端(客户端)与ServerSocket类(服务器端)

Socket与ServerSocket都是基于TCP(有连接的,可靠的传输服务)

Socket类(客户端)的常用方法:

方法描述
public Socket(String host, int port)创建一个套接字,连接到指定主机名和端口号
public OutputStream getOutputStream()返回此套接字的输出流,用于向服务器发送数据,一般使用PrintStream
public InputStream getInputStream()返回此套接字的输入流,用于从服务器接收数据

ServerSocket类(服务器端)的常用方法:

方法描述
ServerSocket(int port)创建一个服务器套接字,绑定到指定的端口号
Socket accept()监听并接受客户端的连接请求,返回一个与客户端通信的新的 Socket 对象
void close()关闭服务器套接字,停止监听客户端连接请求

 Echo模型实现案例代码:
1.服务器端代码实现:

package Example1903;import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.Scanner;//服务器端
public class javaDemo {public static void main(String[] args) throws  Exception{Date date = new Date();ServerSocket server = new ServerSocket(9999);System.out.println("等待客户端运行--------");Socket client = server.accept();//        设置服务器的输入输出流保证能接收信息与输入信息Scanner scanner = new Scanner(client.getInputStream());PrintStream out = new PrintStream(client.getOutputStream());//        接收信息并且将信息传入out输出流boolean flag = true;scanner.useDelimiter("\n");while (flag){if (scanner.hasNext()){String value = scanner.next().trim();if ("byebye".equalsIgnoreCase(value)){out.println("ByeBye");flag = false;}else out.println(date+ "[服务器]发送消息:"+value);}}
//        关闭所有服务server.close();client.close();scanner.close();out.close();}
}

2.客户端代码实现:

package Example1904;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Date;
import java.util.Scanner;//客户端
public class javaDemo {
//    通过键盘输入信息private static final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in));public  static String  getString(String promp) throws  Exception{System.out.print(promp);String str = KEYBOARD_INPUT.readLine();return  str;}public static void main(String[] args)throws Exception {Date date = new Date();Socket client = new Socket("localhost",9999);//        获取同样的输入输出对象Scanner scanner = new Scanner(client.getInputStream());PrintStream out = new PrintStream(client.getOutputStream());scanner.useDelimiter("\n");//使用分隔符boolean flag = true;while (flag){String input = getString( date+ "[客户端]请输入要发送的信息:").trim();out.println(input);//将input内容放入PrintStream流中if (scanner.hasNext()){System.out.println(scanner.next());}if ("byebye".equalsIgnoreCase(input)){flag = false;}}}
}

服务器端运行结果

 客户端运行结果:

代码流程:

  1. 服务器端启动并等待连接:服务器启动后,通过 ServerSocket 监听指定端口(此处为9999),并调用 accept 方法等待客户端连接。一旦有客户端连接成功,服务器会创建一个新的线程来处理与该客户端的通信。

  2. 客户端连接服务器:客户端通过 Socket 构造函数连接到指定的服务器地址(此处为 localhost)和端口号(此处为 9999)。

  3. 客户端发送消息:客户端通过 getString 方法获取用户输入的消息,并将消息通过 PrintStreamprintln 方法发送给服务器。

  4. 服务器接收消息:服务器端在自己的线程中,通过 Scannernext 方法读取客户端发送的消息。

  5. 服务器处理消息:服务器端根据接收到的消息进行相应的处理,可以是对消息进行解析、判断、计算等操作。在这个示例中,服务器端简单地将接收到的消息原样发送回客户端。

  6. 服务器返回消息:服务器通过 PrintStreamprintln 方法将处理后的消息发送给客户端。

  7. 客户端接收消息:客户端通过 Scannernext 方法读取服务器返回的消息,并将其打印到控制台。

  8. 重复步骤3-7,直到客户端发送"byebye",表示结束通信。

答疑:

问1:两个代码是如何实现通信的 ?

首先两个进程之间的通信一定需要接收好对应的端口(计算机网络应用层知识)才能进行通信,然后两个代码共用了输入输出流(可以理解为两个人用了同一条电话线),客户端通过其输出流out将信息输出到服务器端,对于服务器外部输入就是输入流,即输出流变成了服务器的输入流,服务器通过scanner输入流接收客户端输出流的信息,同理服务器也通过其输出流输出到客户端,客户端接收到信息就输出

问2:scanner.useDelimiter("\n");useDelimiter方法知道是设置分隔符,但是搭配"\n"是有什么作用吗?

scanner.useDelimiter("\n"); 设置了扫描器的分隔符为"\n",即换行符。这样做的作用是让扫描器以每一行作为一个输入元素,而不是以空白字符(默认情况下)作为分隔符。在这个示例中,服务器和客户端之间通过换行符来分隔消息的发送和接收。

问3:为什么要用到PrintStream正常的输出System.out.println代替不可以吗?

可以使用System.out.println 来替代PrintStream,它们都用于向控制台输出内容。示例代码中使用 PrintStream 是为了将客户端发送给服务器的消息发送出去,以及将服务器返回的消息打印到客户端的控制台。

问4:服务器端用Scanner(socket.InputStream)是为了获取客户端数据这个可以理解,但是客户端为什么也是用Scanner(socket.InputStream)也是获取客户端?

在客户端和服务器端都使用 Scanner(socket.getInputStream()) 是因为它们需要从对应的套接字(socket)的输入流中读取数据。客户端需要读取服务器发送过来的消息,而服务器需要读取客户端发送过来的消息。

问5:为什么要有private static final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in));代码,不能直接通过Scanner(System.in)替代吗?

private static final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in)); 这段代码定义了一个静态的、只读的 BufferedReader 类型的变量,通过 System.in 将键盘输入流与该变量关联起来。这样做的目的是为了在客户端使用 KEYBOARD_INPUT.readLine() 来获取用户输入的字符串。由于 Scanner(System.in) 是使用缓冲区扫描输入,并不能满足逐行读取的需求,因此需要使用 BufferedReader 来实现。


3.BIO处理模型(实现多用户访问同个服务器)

由于上一个模型里面一段时间只能有一个用户与服务器进行交互,并且一旦用户输入byebye服务器也就随之关闭,但是如果我想要有多个用户去与服务器交互那么该如何实现呢?所以引入了BIO处理模型。

如图结构可以知道,其解决方法是在ServeSocket内部创建多个Socket实例,并且将每一个Socket实例都封装在一个线程内,实现多线程通信,当有用户连接时候就创建一个独立的通信线程,每个用户可以独立关闭自己的线程

所以只需要修改服务器端的代码

服务器端:

package Example1907;import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;class EchoServer implements Runnable {
//    初始化Socket client = null;Scanner scanner = null;PrintStream out = null;boolean flag = true;//    传入通信对象实现创建输入输出流与确认客户端对象public EchoServer(Socket client){try {this.client = client;this.scanner = new Scanner(client.getInputStream());this.out = new PrintStream(client.getOutputStream());}catch (Exception e){e.printStackTrace();}}
//    实现通信@Overridepublic void run() {while (this.flag){String value = scanner.nextLine().trim();if (value.equalsIgnoreCase("byebye")){this.flag = false;out.println("Bye Bye~");}else {out.println("[服务器端]:"+value);}}
//        实现完通信则关闭所有服务try {scanner.close();out.close();client.close();}catch (Exception e){e.printStackTrace();}}}
//服务器端
public class javaDemo  {public static void main(String[] args) throws  Exception {ServerSocket server = new ServerSocket(9999);boolean flag = true;System.out.println("等待客户端连接---------");
//        通过多线程接收多个客户端while (flag){Socket client = server.accept();new Thread(new EchoServer(client)).start();}}}

客户端:还是一样的(这里可以锻炼自己重写一遍代码)

package Example1908;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;//客户端
public class javaDemo {private  static  final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in));public static String getString(String promp)throws  Exception{System.out.print(promp);String input = KEYBOARD_INPUT.readLine().trim();return input;}public static void main(String[] args) throws Exception{Socket client = new Socket("localhost",9999);Scanner scanner = new Scanner(client.getInputStream());PrintStream out = new PrintStream(client.getOutputStream());scanner.useDelimiter("\n");boolean flag = true;while (flag){String msg = getString("[客户端]请输入你想要发送的消息").trim();out.println(msg);if (scanner.hasNext()){System.out.println(scanner.next().trim());}if ("byebye".equalsIgnoreCase(msg)){flag = false;}}scanner.close();out.close();client.close();}
}

效果展示:

服务器端:

以下javaDemo2是用户1,javaDemo4是用户2

客户端1:

客户端2:

这种模型是BIO模式,但是可以发现这里没有对线程数量的限制,也就意味着一旦用户数量急剧增加的时候就会出现性能大幅下降的情况所以需要追加对线程的限制, 也就是真正的BIO(Blocking Io 阻塞Io的模式)


4.UDP程序

UDP传输与Tcp不同的是其面向的是无连接的,不可靠的通信,如果Tcp是打电话,必须要知道对方号码建立连接才能进行通信,那么UDP就是在大街上随便喊一嗓子,有些人就听得到你说的话,也有些人离你太远听不到,但是你并不在乎。

这种传输方式常用于游戏之中,所谓的丢包就是因为udp并不可靠出现的问题,但是这种传输方式非常快延迟低。

UDP常用类有

DatagramPackage的常用方法:

方法名描述
public DatagramPacket(byte[] buf, int length)构造一个 DatagramPacket 对象,使用指定的字节数组作为数据,指定的长度作为有效数据的长度。
public byte[] getData()获取该 DatagramPacket 对象中的数据字节数组。
public int getLength()获取该 DatagramPacket 对象中数据的长度。

DatagramSocket的常用方法:

方法名描述
DatagramSocket()创建一个未绑定的数据报套接字。
DatagramSocket(int port)创建一个绑定到指定端口的数据报套接字。
DatagramSocket(int port, InetAddress address)创建一个绑定到指定端口和指定本地 IP 地址的数据报套接字。
void send(DatagramPacket packet)发送指定的数据包到目的地。
void receive(DatagramPacket packet)接收一个数据包,并将其存储在指定的数据包对象中

 以下案例实现一个客户端通过udp发送报文到服务器并输出服务器返回值

在上一个服务器开着的前提下:

package Example1910;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;public class javaDemo {public static void main(String[] args)throws Exception {
//        通过键盘输入数据System.out.println("请输入你想要发送的数据");BufferedReader input = new BufferedReader(new InputStreamReader(System.in));String data = input.readLine();
//      发送数据包DatagramSocket client = new DatagramSocket(9999);DatagramPacket packet = new DatagramPacket(data.getBytes(StandardCharsets.UTF_8),0,data.length(), InetAddress.getByName("localhost"),9999);client.send(packet);
//        接收数据包byte redata[] = new byte[1024];DatagramPacket repacket = new DatagramPacket(redata,0,redata.length);client.receive(repacket);System.out.println("接收的数据是"+new String(redata,0,redata.length,StandardCharsets.UTF_8));client.close();}
}

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

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

相关文章

QtWebApp开发https服务器,完成客户端与服务器基于ssl的双向认证

引言:所谓http协议,本质上也是基于TCP/IP上服务器与客户端请求和应答的标准,web开发中常用的http server有apache和nginx。Qt程序作为http client可以使用QNetworkAccessManager很方便的进行http相关的操作。Qt本身并没有http server相关的库…

使用Git在GitHub上部署静态页面

在GitHub中,我们可以将自己的静态页面部署到GitHub中,它会给我们提供一个地址使得我们的页面变成一个真正的网站,可以供用户访问。 一、在GitHub下创建仓库 二、将项目部署到GitHub上 1. 初始化Git仓库 2. 提交代码 3. 关联远程仓库 在Gi…

【java安全】原生反序列化利用链JDK7u21

文章目录 【java安全】原生反序列化利用链JDK7u21前言原理equalsImpl()如何调用equalsImpl()?HashSet通过反序列化间接执行equals()方法如何使hash相等? 思路整理POCGadget为什么在HashSet#add()前要将HashMap的value设为其他值? 【java安全】…

WSL1升级为WSL2

首先需要启用组件 使用管理员打开Powershell并运行 Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform启用后会要求重启计算机 从https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi获取WSL2 Linux内核更新包,…

HTML 是什么?它的全称是什么?

聚沙成塔每天进步一点点 专栏简介HTML是什么?HTML的全称是什么?写在最后 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对We…

ad+硬件每日学习十个知识点(16)23.7.27 (总线保持、lin报文、逻辑器件手册解读)

文章目录 1.总线保持是怎么实现的?有什么需要注意的(驱动电流和电阻)?2.LIN报文3.芯片datasheet的features、applications、description看完,应该能大致判断逻辑器件能否满足我们的要求。4.什么是逻辑器件的传输延时&a…

WiFi无线组网温湿度实时监测系统

近年来随着我国电子技术和无线通信技术的快速发展,远距离数据采集传输被应用到众多领域,由于事关环境安全和生命健康,受到了各行各界的关注。在温湿度监测中,目前采用的通信技术主要是4G、WiFi、以太网、LoRa等,今天&a…

docker删除容器(步骤详解)

要在Docker中删除容器,需要使用命令docker rm。 下面是详细步骤: 1. 首先,使用docker ps命令查看当前正在运行的容器。这个命令会列出所有正在运行的容器的ID、名称、状态等信息。 如果没有正在运行的容器可以通过docker ps -a 查看当前所…

[Qt]FrameLessWindow实现调整大小、移动弹窗并具有Aero效果

说明 我们知道QWidget等设置了this->setWindowFlags(Qt::FramelessWindowHint);后无法移动和调整大小,但实际项目中是需要窗口能够调整大小的。所以以实现FrameLess弹窗调整大小及移动弹窗需求,并且在Windows 10上有Aero效果。 先看一下效果&#xf…

zabbix监控mysql容器主从同步状态并告警钉钉/企业微信

前言:被监控的主机已经安装和配置mysql主从同步,和zabbix-agent插件。 mysql创建主从同步:http://t.csdn.cn/P4MYq centos安装zabbix-agent2:http://t.csdn.cn/fx74i mysql主从同步,主要监控这2个参数指标&#xf…

Python入门【​编辑、组合、设计模式_工厂模式实现 、设计模式_单例模式实现、工厂和单例模式结合、异常是什么?异常的解决思路 】(十七)

👏作者简介:大家好,我是爱敲代码的小王,CSDN博客博主,Python小白 📕系列专栏:python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 📧如果文章知识点有错误…

弘扬“两弹一星”精神,勇攀科学技术高峰——道本科技商业大学党日活动圆满落幕

2023年8月2日,道本科技与商业大学携手举办了一场主题为“弘扬‘两弹一星’精神,勇攀科学技术高峰”的党日活动。本次活动旨在了解党领导下的中国核工业发展历程,传承和弘扬“两弹一星”精神,同时展示道本科技创新产品,…

ThinkPHP5使用phpqrcode生成二维码

生成指定跳转地址二维码图片: 首先将下载好的phpqrcode.php文件放到指定目录内(我这里用的放在public/phpqrcode目录下),准备调用 之后控制器中调用 public function qrcode(){require_once "./phpqrcode/phpqrcode.php&quo…

opencv-33 图像平滑处理-中值滤波cv2.medianBlur()

中值滤波是一种常见的图像处理滤波技术,用于去除图像中的噪声。它的原理是用一个滑动窗口(也称为卷积核)在图像上移动,对窗口中的像素值进行排序,然后用窗口中像素值的中值来替换中心像素的值。这样,中值滤…

SHELL——备份脚本

编写脚本,使用mysqldump实现分库分表备份。 1、获取分库备份的库名列表 [rootweb01 scripts]# mysql -uroot -p123456 -e "show databases;" | egrep -v "Database|information_schema|mysql|performance_schema|sys" mysql: [Warning] Using …

游戏开发人员如何从 Splashtop 中受益

游戏开发时代在不断发展,远程办公、协作和高性能需求变得越来越普遍。因此,对复杂工具的需求不断增加,这些工具不仅可以满足这些需求,还可以为开发人员提供无缝体验。 其中一个工具是 Splashtop Business Access Performance&…

Redis持久化两种方案以及对比差异

1.1.RDB持久化 RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件称为R…

2023网络安全学习路线 非常详细 推荐学习

首先咱们聊聊,学习网络安全方向通常会有哪些问题 1、打基础时间太长 学基础花费很长时间,光语言都有几门,有些人会倒在学习 linux 系统及命令的路上,更多的人会倒在学习语言上; 2、知识点掌握程度不清楚 对于网络安…

微信多开(双开三开均可,且不局限于微信,其他设备亦可)

1.鼠标右键“微信”,属性 如上图,自动选取的,别动,然后CtrlC,,,,结果如下 "C:\Program Files (x86)\Tencent\WeChat\WeChat.exe" 2.创建文本,电脑桌面空白处单击,新建,文本档案&#…

小白玩转浏览器开发者工具—F12(超详细)

目录 1、检查元素:🚀 2、修改样式:🛫 3、调试代码:👑 4、网络分析:🚂 5、控制台输出:🚁 6、移动设备模拟:🎨 7、缓存管理&…