JAVA—网络通信

2024-09-05 18:20
文章标签 java 网络通信

本文主要是介绍JAVA—网络通信,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        本文是学习网络通信入门和简单了解UDP协议和TCP协议,学习和了解CS架构和简单了解BS架构和HTTP协议(部分图片来自黑马程序员)

目录

1.网络通信三要素

(1)IP地址

(2)端口号

(3)协议

2.UDP通信—快速入门

3.UDP通信—多发多收

4.TCP通信—快速入门

5.TCP通信—多发多收

6.TCP通信—同时接收多个客户端

7.TCP通信—综合案例

(1)即时通信-群聊

(2)实现一个简易的BS架构

 *线程优化


网络编程

可以让设备中的程序与网络其他设备中的程序进行数据交互

基本通信框架

有两种形式:CS架构(CLient客户端/Server服务器)和 BS架构(Browser浏览器/Server服务器)

1.网络通信三要素

(1)IP地址

  • IP(InternetProtocol)全称“互联网协议地址”,是分配给上网设备的唯一标志
  • 有两种形式 IPV4 和 IPV6

    IPV4 由四个字节组成一般使用点分十进制表示法

    IPV6 由8段组成 一段每四位编码成一个十六进制数 一般使用冒分十六进制表示 

127.0.0.1/ localhost  代表本机IP,只会寻求当前所在的主机

InetAddress

 代表IP地址

名称说明
public static InetAddress getLocalHost()读取本机IP,会以一个inetAddress的对象返回
public static  InetAddress getByname(String host)

根据ip地址或者域名 返回一个inetAddress对象

public String getHostName()获取该IP地址对象对应的主机名
public String getHostAddress()获取该IP地址中的IP地址信息
public boolean isReachable(int timeout)在指定毫秒内,判断主机与该IP是否能连通

(2)端口号

  • 标记正在计算机设备上运行的应用程序 被固定为一个16位的二进制 范围是0~65535

        分类

  • 周知端口:0~1023 被预先定义的知名应用占用(如HTTP占用80,FTP占用21)
  • 注册端口:1024~49151 分配给用户或某些应用程序
  • 动态端口:49152~65535 一般不固定分配某种进程,而是动态分配

        注意:我们自己开发的程序一般选择使用注册端口,且一个设备不能出现两个程序的端口号一致,否则出错

(3)协议

        网络上通信的设备 事先固定的连接规则 以及传输数据的规则被称为网络通信协议

 UDP协议 (通信效率高 用于语音 视频通话)

  • 特点:无连接,不可靠通信
  • 不事先建立连接数据,按照包发一包数据包含自己的IP程序端口,目的地IP程序端口的数据限制在64kb内的。
  • 发送方不管对方是否在线树立在中间丢失也不管如果接受方式的数据也不返回确认故而不可靠

 TCP协议 (通信效率相对不高 网页 文件下载,支付)

  • 特点:面向连接 可靠通信
  • TCP的最终目的:要保障在不可信的信道上实现可靠的传输
  • 主要三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接(确保双方数据的收发都已经完成)
  • 三次握手

2.UDP通信—快速入门

 实现单发单收

package IP_Study.upd01;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;public class Client {public static void main(String[] args) throws Exception {// 1.创建客户端DatagramSocket socket = new DatagramSocket();// 2.创建数据包// public DatagramPacket(byte buff[], int offset, int length,//                          InetAddress address, int port)//            参数一:封装要发出去的数据//            参数二:发送要发出去的数据大小(字节个数)//            参数三:服务端的IP地址//            参数四:服务端程序的端口String rs = "万水千山 我陪你去看";byte[] buff = rs.getBytes();DatagramPacket packet = new DatagramPacket(buff,buff.length, InetAddress.getLocalHost(),8088);// 3.正式发送这个数据包数据socket.send(packet);System.out.println("客户端数据发送完毕");socket.close(); //关闭流 释放资源}
}
package IP_Study.upd01;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class Server {public static void main(String[] args) throws Exception {// 1.创建一个服务端对象DatagramSocket socket = new DatagramSocket(8088);System.out.println("服务端启动");// 2.创建一个数据包对象,用于接收数据byte [] buffer = new byte[1024 *64]; //64KBDatagramPacket packet = new DatagramPacket(buffer, buffer.length);// 3.正式使用数据包来接收客户端发来的数据socket.receive(packet);// 4.从字节数组中 打印接收的数据int len = packet.getLength();String rs = new String(buffer,0, len);System.out.println(rs);System.out.println(packet.getAddress().getHostAddress()); //获取发起IP}
}

3.UDP通信—多发多收

改造UDP单发单收代码已实现多发多收

package IP_Study.upd01;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception {// 1.创建客户端DatagramSocket socket = new DatagramSocket();// 2.创建数据包// public DatagramPacket(byte buff[], int offset, int length,//                          InetAddress address, int port)//            参数一:封装要发出去的数据//            参数二:发送要发出去的数据大小(字节个数)//            参数三:服务端的IP地址//            参数四:服务端程序的端口Scanner sc = new Scanner(System.in);while (true) {System.out.println("请说:");String rs = sc.next();//一旦发现客户输入exit 则退出客户端if("exit".equals(rs)){System.out.println("退出成功");socket.close();break;}byte[] buff = rs.getBytes();DatagramPacket packet = new DatagramPacket(buff,buff.length, InetAddress.getLocalHost(),8088);// 3.正式发送这个数据包数据socket.send(packet);}}
}
package IP_Study.upd01;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class Server {public static void main(String[] args) throws Exception {// 1.创建一个服务端对象DatagramSocket socket = new DatagramSocket(8088);System.out.println("服务端启动");// 2.创建一个数据包对象,用于接收数据byte [] buffer = new byte[1024 *64]; //64KBDatagramPacket packet = new DatagramPacket(buffer, buffer.length);while (true) {// 3.正式使用数据包来接收客户端发来的数据socket.receive(packet);// 4.从字节数组中 打印接收的数据int len = packet.getLength();String rs = new String(buffer,0, len);System.out.println(rs);System.out.println(packet.getAddress().getHostAddress()); //获取发起IPSystem.out.println(packet.getPort());System.out.println("---------------");}}
}

4.TCP通信—快速入门

package IP_Study.tcp01;import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class Client {public static void main(String[] args) throws Exception {// 1.创建socket对象 并同时请求与服务端程序的连接Socket socket = new Socket("127.0.0.1",8888);// 2.从Socket中得到一个字节输出流并包装成数据输出流OutputStream os = socket.getOutputStream();// 3.把低级的字节输出流包装成数据输出流DataOutputStream dos = new DataOutputStream(os);// 4.开始写出数据dos.writeUTF("万水千山");dos.close();socket.close(); //释放资源}
}
package IP_Study.tcp01;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws Exception {// 1.创建ServerSocket对象,同时为服务器注册端口ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务端启动成功");// 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求Socket socket = serverSocket.accept();// 3.从Socket中获得一个字节数入流管道InputStream is = socket.getInputStream();// 4.把原始的字节输入流包装成数据输入流DataInputStream dis = new DataInputStream(is);// 5.使用数据输入流读取客户端发送的消息String rs = dis.readUTF(); //信息格式要统一System.out.println(rs);// 获取客户端的IP地址System.out.println(socket.getRemoteSocketAddress());dis.close();socket.close();}
}


5.TCP通信—多发多收

package IP_Study.tcp01;import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception {// 1.创建socket对象 并同时请求与服务端程序的连接Socket socket = new Socket("127.0.0.1",8888);// 2.从Socket中得到一个字节输出流并包装成数据输出流OutputStream os = socket.getOutputStream();// 3.把低级的字节输出流包装成数据输出流DataOutputStream dos = new DataOutputStream(os);Scanner sc = new Scanner(System.in);while (true) {// 4.开始写出数据System.out.println("请说");String rs = sc.nextLine();// 一旦输入 exit 就退出客户端if("exit".equals(rs)){System.out.println("退出成功");dos.close();socket.close();break;}dos.writeUTF(rs);dos.flush(); //刷新数据流 以免数据没有发出去}}
}
package IP_Study.tcp01;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws Exception {// 1.创建ServerSocket对象,同时为服务器注册端口ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务端启动成功");// 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求Socket socket = serverSocket.accept();// 3.从Socket中获得一个字节数入流管道InputStream is = socket.getInputStream();// 4.把原始的字节输入流包装成数据输入流DataInputStream dis = new DataInputStream(is);while (true) {// 5.使用数据输入流读取客户端发送的消息try {String rs = dis.readUTF(); //信息格式要统一System.out.println(rs);// 获取客户端的IP地址System.out.println(socket.getRemoteSocketAddress());} catch (Exception e) {System.out.println(socket.getRemoteSocketAddress() + "离线了");dis.close();socket.close();break;}}}
}

         此时的代码是不能实现与多个客户端进行通信的 因为服务器只搭建一个通道


6.TCP通信—同时接收多个客户端

改造代码时 不能单纯依靠死循环 还需要使用线程技术进行处理

package IP_Study.tcp01;import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception {// 1.创建socket对象 并同时请求与服务端程序的连接Socket socket = new Socket("127.0.0.1",8888);// 2.从Socket中得到一个字节输出流并包装成数据输出流OutputStream os = socket.getOutputStream();// 3.把低级的字节输出流包装成数据输出流DataOutputStream dos = new DataOutputStream(os);Scanner sc = new Scanner(System.in);while (true) {// 4.开始写出数据System.out.println("请说");String rs = sc.nextLine();// 一旦输入 exit 就退出客户端if("exit".equals(rs)){System.out.println("退出成功");dos.close();socket.close();break;}dos.writeUTF(rs);dos.flush(); //刷新数据流 以免数据没有发出去}}
}
package IP_Study.tcp01;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws Exception {// 1.创建ServerSocket对象,同时为服务器注册端口ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务端启动成功");while (true) {// 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求Socket socket = serverSocket.accept();System.out.println("有人上线了"+socket.getRemoteSocketAddress());// 把这个客户端的Socket通信管道交给一个独立的线程去完成new SeverReadder(socket).start();}}
}

 使用一个线程类来实现功能

package IP_Study.tcp01;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;public class SeverReadder extends Thread{private Socket socaket;public SeverReadder(Socket socket) {this.socket = socket;}@Overridepublic void run(){// 3.从Socket中获得一个字节数入流管道try {InputStream is = socket.getInputStream();// 4.把原始的字节输入流包装成数据输入流DataInputStream dis = new DataInputStream(is);while (true) {try {// 5.使用数据输入流读取客户端发送的消息String rs = dis.readUTF(); //信息格式要统一System.out.println(rs);// 获取客户端的IP地址System.out.println(socket.getRemoteSocketAddress());} catch (IOException e) {System.out.println(socket.getRemoteSocketAddress() + "离线了");dis.close();socket.close();break;}}} catch (Exception e) {e.printStackTrace();}}
}

7.TCP通信—综合案例

(1)即时通信-群聊

    TCP通信-端口转发 实现思路是将存储好当前在线的socket都进行一次信息发送

package IP_Study.tcp01;import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception {// 1.创建socket对象 并同时请求与服务端程序的连接Socket socket = new Socket("127.0.0.1",8888);// 创建一个独立线程 负责随机从socket中接收服务器发送的信息new ClientReader(socket);// 2.从Socket中得到一个字节输出流并包装成数据输出流OutputStream os = socket.getOutputStream();// 3.把低级的字节输出流包装成数据输出流DataOutputStream dos = new DataOutputStream(os);Scanner sc = new Scanner(System.in);while (true) {// 4.开始写出数据System.out.println("请说");String rs = sc.nextLine();// 一旦输入 exit 就退出客户端if("exit".equals(rs)){System.out.println("退出成功");dos.close();socket.close();break;}dos.writeUTF(rs);dos.flush(); //刷新数据流 以免数据没有发出去}}
}
package IP_Study.tcp01;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;public class ClientReader extends Thread{private Socket socket;public ClientReader(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {InputStream is = socket.getInputStream();// 4.把原始的字节输入流包装成数据输入流DataInputStream dis = new DataInputStream(is);while (true) {try {// 5.使用数据输入流读取客户端发送的消息String rs = dis.readUTF(); //信息格式要统一System.out.println(rs);// 获取客户端的IP地址System.out.println(socket.getRemoteSocketAddress());} catch (IOException e) {System.out.println("自己离线了"+socket.getRemoteSocketAddress());dis.close();socket.close();break;}}} catch (Exception e) {e.printStackTrace();}}}
package IP_Study.tcp01;import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;public class Server {public static List<Socket> onLineSockets = new ArrayList<>();public static void main(String[] args) throws Exception {// 1.创建ServerSocket对象,同时为服务器注册端口ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务端启动成功");while (true) {// 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求Socket socket = serverSocket.accept();onLineSockets.add(socket);System.out.println("有人上线了"+socket.getRemoteSocketAddress());// 把这个客户端的Socket通信管道交给一个独立的线程去完成new SeverReader(socket).start();}}
}
package IP_Study.tcp01;import java.io.*;
import java.net.Socket;public class SeverReader extends Thread{private Socket socket;public SeverReader(Socket socket) {this.socket = socket;}@Overridepublic void run(){// 3.从Socket中获得一个字节数入流管道try {InputStream is = socket.getInputStream();// 4.把原始的字节输入流包装成数据输入流DataInputStream dis = new DataInputStream(is);while (true) {try {// 5.使用数据输入流读取客户端发送的消息String rs = dis.readUTF(); //信息格式要统一System.out.println(rs);//把这个信息发给全部客户端进行接收SendMsgToAll(rs);// 获取客户端的IP地址System.out.println(socket.getRemoteSocketAddress());} catch (IOException e) {System.out.println(socket.getRemoteSocketAddress() + "离线了");Server.onLineSockets.remove(socket);dis.close();socket.close();break;}}} catch (Exception e) {e.printStackTrace();}}private void SendMsgToAll(String rs) throws Exception {// 发送给全部在线的socket管道接受for (Socket onLineSocket : Server.onLineSockets) {OutputStream os = onLineSocket.getOutputStream();DataOutputStream dos = new DataOutputStream(os);dos.writeUTF(rs);dos.flush();}}
}

 实现思路:

当客户端有信息传输到服务器中,先将信息在服务端调用,在向所有在线的通信管道传输信息

(2)实现一个简易的BS架构

package IP_Study.tcp02;import IP_Study.tcp01.SeverReader;import java.net.ServerSocket;
import java.net.Socket;public class Sever {public static void main(String[] args) throws Exception {// 1.创建ServerSocket对象,同时为服务器注册端口ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务端启动成功");while (true) {// 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求Socket socket = serverSocket.accept();System.out.println("有人上线了"+socket.getRemoteSocketAddress());// 把这个客户端的Socket通信管道交给一个独立的线程去完成new SeverReader(socket).start();}}
}
package IP_Study.tcp02;import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;public class SeverReader extends Thread{private Socket socket;public SeverReader(Socket socket) {this.socket = socket;}@Overridepublic void run() {// 响应一个网页内容try {OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);ps.println("HTTP/1.1 200 OK");ps.println("Content-Type:text/html;charset=UTF-8");ps.println();//必须换行ps.println("<div style='color:purple;font-size:101px;text-align:center' >万水千山 我陪你去看");ps.close();socket.close();} catch (IOException e) {e.printStackTrace();}}
}

 *线程优化

  在高并发下 处理任务容易宕机 所以使用线程池来处理线程(注意线程池的参数)

package IP_Study.tcp02;import IP_Study.tcp01.SeverReader;import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class Sever {public static void main(String[] args) throws Exception {// 1.创建ServerSocket对象,同时为服务器注册端口ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务端启动成功");// 创建线程池 负责处理通信管道任务ThreadPoolExecutor pool = new ThreadPoolExecutor(16 * 2, 16 * 2, 0, TimeUnit.SECONDS,new ArrayBlockingQueue<>(8), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());while (true) {// 2.使用ServerSocket对象 带哦用一个accept方法 等待客户端连接请求Socket socket = serverSocket.accept();pool.execute(new SeverReader(socket));System.out.println("有人上线了"+socket.getRemoteSocketAddress());// 把这个客户端的Socket通信管道交给一个独立的线程去完成new SeverReader(socket).start();}}
}

                                                                                                        学习时间:2024.09.04

这篇关于JAVA—网络通信的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139713

相关文章

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例:

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.