当前位置: 首页 > article >正文

JavaSE——网络编程

一、InetAddress类

        InetAddress是Java中用于封装IP地址的类。

获取本机的InetAddress对象:

InetAddress localHost = InetAddress.getLocalHost();

根据指定的主机名获取InetAddress对象(比如说域名)

InetAddress host = InetAddress.getByName("www.baidu.com");

通过InetAddress对象获取对应的地址 

String hostAddress = host.getHostAddress();

通过InetAddress对象获取对应的主机名或者是域名

String hostAName = host.getHostName();

二、Socket 

        套接字(Socket)在开发网络应用程序中被广泛采用,以至于称为事实上的标准,它允许数据在两个Socket间通过IO传输。

流式套接字

        基于TCP协议,提供面向连接、可靠的数据传输服务。它保证数据的顺序性、完整性和可靠性,适用于对数据传输质量要求较高的场景,如文件传输、远程登录等。在Java中,使用Socket类来表示流式套接字。

数据报套接字

        基于UDP协议,提供无连接、不可靠的数据传输服务。它不保证数据的顺序性、完整性和可靠性,但传输速度快,适用于对实时性要求较高、对数据丢失不敏感的场景,如视频直播、在线游戏等。在Java中,使用DatagramScoket类和DatagramPacket类来实现数据报套接字通信。

        一般来讲,主动发起通信的应用程序属于客户端,等待通信请求的为服务端。

三、TCP网络通信编程

3.1TCP套接字通信原理

3.1.1服务端

  1. 创建ServerSocket:服务器端首先创建一个ServerSocket对象,并绑定到一个特定的端口,等待客户端的连接请求。

    ServerSocket ss = new ServerSocket(8888);

    表示服务器端在本地的 8888 端口上创建一个ServerSocket,准备接收客户端的连接。

  2. 监听连接请求:服务器端通过ServerSocket的accept方法监听客户端的连接请求。当没有客户端发起连接请求时,accept方法会阻塞等待,直到接收到一个连接请求,然后返回一个新的Socket对象,该Socket对象代表了服务器端与客户端之间的连接。

    Socket socket = ss.accept();

    表示服务器端接受了一个客户端的连接请求,并创建了一个新的Socket对象来与该客户端进行通信。

  3. 数据传输:可以使用socket.getInputStream()获取输入流,用于接收客户端发送的数据;使用socket.getOutStream()获取输出流,用于向客户端发送数据。

  4. 关闭连接:数据传输完成后,服务器端需要关闭与客户端的连接,释放资源。

3.1.2客户端

  1. 创建Socket:客户端创建一个Socket对象,并指定服务器端的IP地址和端口号,发起连接请求。
    Socket socket = new Socket(InetAddress.getLocalHost(),8888);
  2. 数据传输:连接建立后,客户端通过Socket对象的输入流和输出流与服务器端进行数据传输。与服务器端类似,客户端也可以使用socket.getInputStream和socket.OutputStream获取输入流和输出流,进行数据的读写操作。

  3. 关闭连接:数据传输完成后,客户端需要关闭连接,释放资源。

3.2TCP字节流编程实例

        要求客户端向服务端发送hello serve,服务端受到后返回hello client。

服务端:

//1. 在本机 的 9999 端口监听, 等待连接
// 细节: 要求在本机没有其它服务在监听 9999
// 细节:这个 ServerSocket 可以通过 accept() 返回多个 Socket[多个客户端连接服务器的并发]
ServerSocket ss = new ServerSocket(8888);
System.out.println("客户端监听中");

//如果没有客户端来连接,程序会阻塞等待连接
//如果有客户端连接则会返回socket对象,程序继续
Socket socket = ss.accept();
System.out.println("客户端IP" + socket.getInetAddress().getHostAddress());

//2.通过socket.getInputstream()读取客户端写入到数据通道的数据
InputStream inputstream = socket.getInputStream();

//IO读取
int readln = 0;
byte[] bytes = new byte[1024];
while((readln = inputstream.read(bytes)) != -1){
    System.out.println(new String(bytes,0,readln));
}
socket.shutdownInput();

//3.通过socket.getOutputStream()给客户端发送数据
OutputStream outputstream = socket.getOutputStream();
outputstream.write("hello client".getBytes());

//4.关闭流和socket
inputstream.close();
outputstream.close();
socket.close();
System.out.println("服务端退出");

客户端:

//1.连接服务端
Socket socket = new Socket(InetAddress.getLocalHost(),8888);
System.out.println("服务端IP" + socket.getInetAddress().getHostAddress());

//2.连接上后,生成Socket,通过socket.getOutputstream()得到与socket对象相关连的输出流对象
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
//通过输出流,写入数据到数据通道
outputStream.write("hello serve".getBytes());
//设计结束标记
socket.shutdownOutput();

//通过输入流,从通道中读取数据
byte[] buf = new byte[1024];
int readln = 0;
while ((readln = inputStream.read(buf)) != -1) {
    System.out.println(new String(buf, 0, readln));
}

//3.关闭流和对象
outputStream.close();
inputStream.close();
socket.close();
System.out.println("客户端已关闭");

3.3TCP文件上传 

3.3.1一个工具类

public class StreamUtils {
	/**
	 * 功能:将输入流转换成byte[]
	 * @param is
	 * @return
	 * @throws Exception
	 */
	public static byte[] streamToByteArray(InputStream is) throws Exception{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
		byte[] b = new byte[1024];
		int len;
		while((len=is.read(b))!=-1){
			bos.write(b, 0, len);	
		}
		byte[] array = bos.toByteArray();
		bos.close();
		return array;
	}
	/**
	 * 功能:将InputStream转换成String
	 * @param is
	 * @return
	 * @throws Exception
	 */
	
	public static String streamToString(InputStream is) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder builder= new StringBuilder();
		String line;
		while((line=reader.readLine())!=null){ //当读取到 null时,就表示结束
			builder.append(line+"\r\n");
		}
		return builder.toString();
		
	}

}

        只需要知道这里的streamToByteArray方法将输入流的数据转换为byte[],streamToString方法将输入流转换为String。

3.3.2思路分析 

        先将磁盘上的图片转换成文件字节数组,通过Socket传输给服务端,服务端将得到的bytes文件写入到指定的路径中,向客户端回复 收到图片。

3.3.3服务端

//1.服务端在本机监听8888端口
ServerSocket ss = new ServerSocket(8888);
System.out.println("服务端在8888端口监听");

//2.等待连接
Socket socket = ss.accept();

//3.读取客户端发送的消息
//通过Socket得到输入流

BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);

//4.将得到的bytes数组写入到指定的路径中,就得到一个文件了
String str = "src\\my.jpg";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(str));
bos.write(bytes);
bos.close();

//向客户端回复收到图片
//通过socket获取到输出流(字符)
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("收到图片");
bw.flush();
socket.shutdownOutput();
//关闭其它资源
bw.close();
bis.close();
socket.close();
ss.close();

3.3.4客户端

//1.客户端连接服务端8888,得到Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),8888);

//创建读取磁盘文件的输入流
String filePath = "D:\\My.jpg";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));

//byte就是filePath对应的字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);

//通过socket获取到输出流,将bytes数据发送给服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
bis.close();
socket.shutdownOutput();

//接收从服务端回复的消息
InputStream inputStream = socket.getInputStream();
//使用StreamUtils的方法直接将inputStream读取到的内容转成字符串
String s  = StreamUtils.streamToString(inputStream);
System.out.println(s);

//关闭相应的流
inputStream.close();
bos.close();
socket.close();

3.4TCP文件下载

3.4.1思路分析

         客户端将要下载的文件名传递给服务端,服务端返回对应文件,如果没有就返回默认。

3.4.2服务端

//1.监听 9999端口
ServerSocket serverSocket = new ServerSocket(9999);

//2.等待端口连接
Socket socket = serverSocket.accept();

//读取客户端发送要下载的文件名
InputStream inputStream = socket.getInputStream();
byte[] b = new byte[1024];
int len = 0;
String downLoadFileName = "";
while ((len = inputStream.read(b)) != -1) {
    downLoadFileName += new String(b,0,len);
}
System.out.println("用户希望下载的文件名=" + downLoadFileName);

String resFileName = "";
if("高山流水".equals(downLoadFileName)){
    resFileName = "src\\高山流水.mp3";
}
else resFileName = "src\\无名.mp3";
//4.创建一个输入流,读取文件
BufferedInputStream bis =
        new BufferedInputStream(new FileInputStream(resFileName));

//5.使用工具类StreamUtils,读取文件到一个字节数组
byte[] buffer = StreamUtils.streamToByteArray(bis);

//6.得到Socket相关的输出流
BufferedOutputStream bos =
        new BufferedOutputStream(socket.getOutputStream());

//写入到数据通道,返回给客户端
bos.write(buffer);
socket.shutdownOutput();

//关闭相关资源
bos.close();
bis.close();
socket.close();
serverSocket.close();
System.out.println("服务端退出");

3.4.3客户端 

//1.接收用户输入,指定下载文件名
Scanner sc = new Scanner(System.in);
System.out.println("请指定下载文件名");
String downloadFileName = sc.nextLine();

//2.客户端连接服务端,准备发送
Socket socket = new Socket(InetAddress.getLocalHost(),9999);

//3.获取关联输出流
OutputStream os = socket.getOutputStream();
os.write(downloadFileName.getBytes());
//设置写入结束标志
socket.shutdownOutput();

//4.读取服务端返回的文件
BufferedInputStream bis =
        new BufferedInputStream(socket.getInputStream());
byte[] buffer = StreamUtils.streamToByteArray(bis);

//5.得到一个输出流,准备将bytes写入到磁盘文件
String filePath = "D:\\" + downloadFileName + ".mp3";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(buffer);

//关闭相关资源
bos.close();
bis.close();
os.close();
socket.close();
System.out.println("客户端已退出");

四、UDP网络通信编程

4.1 UDP通信原理

4.1.1发送端

  1. 创建DatagramSocket:发送端创建一个DatagramSocket对象,用于发送数据报。可以不指定端口号,让系统自动分配一个临时端口号;也可以指定一个端口号。
    DatagramSocket socket = new DatagramSocket();
    DatagramSocket socket = new DatagramSocket(8888);
  2. 创建DatagramPacket:发送端创建一个DatagramPacket对象,用于封装要发送的数据。需要指定数据内容、数据长度、接收端的 IP 地址和端口号。
    DatagramPacket packet = 
                        new DatagramPacket(data, data.length, InetAddress.getByName("server_ip"), 8888);
  3. 发送数据报:通过DatagramSocket的send(DatagramPacket p)方法发送数据报。
  4. 关闭DatagramSocket:数据发送完成后,发送端关闭DatagramSocket,释放资源。

4.1.2接收端

  1. 创建DatagramSocket:接收端创建一个DatagramSocket对象,并绑定到一个特定的端口上,用于接收数据报。
    DatagramSocket socket = new DatagramSocket(8888);
  2. 接收数据报:接收端通过DatagramSocket的reveive(Datagrampacket p)方法接收数据报。需要先创建一个Datagrampacket 对象作为接收容器,指定一个足够大的缓冲区来存储接收到的数据。
    byte[] buffer = new byte[1024];
    DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 
    socket.receive(packet);
  3. 处理数据:接收到数据报后,可以通过Datagrampacket对象获取数据内容、发送端的 IP 地址和端口号等信息。
    String receivedData = new String(packet.getData(), 0, packet.getLength()); 
    InetAddress senderAddress = packet.getAddress(); 
    int senderPort = packet.getPort();
  4. 关闭DatagramSocket:数据处理完成后,接收端关闭DatagramSocket,释放资源。

4.2UDP网络编程

4.2.1A端

//1.创建一个DatagramSocket对象,准备在9999端口接收数据
DatagramSocket socket = new DatagramSocket(9999);
//2.构建一个DatagramPacket对象,准备接收数据
//UDP协议一个数据包最大64k
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);

//3.调用接收方法,将通过网络传输的DatagramPacket对象
//  填充到packet对象中
//如果没有数据包发送到本机的9999端口,就会阻塞等待

socket.receive(packet);

//4.可以把packet拆包取出数据,并显示
int len = packet.getLength();//实际接收到的数据字节长度
byte[] data  = packet.getData();//接收到数据
String s = new String(data,0,len);
System.out.println(s);

//5.回复
byte[] buf2 = "好的".getBytes();
DatagramPacket packet2 = new DatagramPacket(buf2, buf2.length, InetAddress.getByName("192.168.31.130"),8888);
socket.send(packet2);
//关闭资源
socket.close();
System.out.println("A端退出");

4.2.2B端 

//1.创建DatagramSocket对象,准备在8888端口接收数据
DatagramSocket socket = new DatagramSocket(8888);

//2.将需要发送的数据封装到DatagramPacket对象中
byte[] data = "hello 明天吃火锅".getBytes();

//封装的DatagramPacket对象: data内容字节数组,data.length,主机IP,端口
DatagramPacket datagramPacket =
        new DatagramPacket(data, data.length, InetAddress.getByName("192.168.31.130"),9999);
socket.send(datagramPacket);

//接收A端的回复
byte[] receiveData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
//拆包
int len = receivePacket.getLength();
byte[] receiveData2 = receivePacket.getData();
String s = new String(receiveData2,0,len);
System.out.println(s);
//关闭资源
socket.close();
System.out.println("B端退出");

 

 

 

 

 

 

 

 

 

 

 


http://www.kler.cn/a/487898.html

相关文章:

  • 深入讲解 Docker 及实践
  • Spring IoC DI 入门 和 使用
  • uniapp实现在card卡片组件内为图片添加长按保存、识别二维码等功能
  • Web枚举:深入了解目标应用系统
  • RK3568 Android 13 内置搜狗输入法小计
  • SpringBoot之核心配置
  • Python基于YOLOv8和OpenCV实现车道线和车辆检测
  • 有机物谱图信息的速查技巧有哪些?
  • 【2025最新计算机毕业设计】基于SpringBoot+Vue奶茶点单系统(高质量源码,提供文档,免费部署到本地)
  • vue3+element-plus暗黑模式切换动画圆弧过渡
  • linux nginx 安装后,发现SSL模块未安装,如何处理?
  • Mumu模拟器和Frida
  • 【读点论文】DepGraph: Towards Any Structural Pruning通用的结构化剪枝框架,处理结构化剪枝的图依赖问题
  • 20250109使用M6000显卡在Ubuntu20.04.6下跑whisper来识别中英文字幕
  • Vue 2 提取可复用 Footer 组件
  • L1G5000 XTuner 微调个人小助手认知
  • 【Vue.js 组件化】高效组件管理与自动化实践指南
  • vs2022开发.net窗体应用开发环境安装配置以及程序发布详细教程
  • STM32 : PWM 基本结构
  • [network]回顾:集线器(Hub)
  • poi-tl+kkviewfile实现生成pdf业务报告
  • 深入Android架构(从线程到AIDL)_21 IPC的Proxy-Stub设计模式03
  • 【C++】C++11(二)
  • 通过 crontab 每天定时启动一个 Java JAR 包并调用特定的 `main` 方法
  • LeetCode599 两个列表的最小索引总和
  • jenkins 调用bat脚本