Java网络编程的笔记小结
发布日期:2021-06-29 20:01:37 浏览次数:2 分类:技术文章

本文共 16685 字,大约阅读时间需要 55 分钟。

Java网络编程的笔记

这篇笔记是针对本人在Java中的网络编程做出的,如果您发现有什么问题或者错误,欢迎指正,本人由衷的表示感谢! ————tyong

文章目录

IP

IP地址对于学习到此处的人来说想必已经都不陌生了,这里我们来看看Java中是如何对IP进行封装的,Java中对网络的IP对应的就是InetAddress类,须知:

  1. InetAddress这个类的构造器已经私有化了
  2. 获取 InetAddress这个类的实例,有如下两个方法:
    • InetAddress getByName(String hostName); // 这个方法可以通过IP地址 或者 域名创建 InetAddress实例(但是注意:前者不会进行DNS域名解析,后者会进行域名解析);
    • InetAddress getLocalHost(); // 获取本机的IP对应的 InetAddress实例;
  3. InetAddress实例的常用方法:
    • String getHostName(); // 获取这个 InetAddress实例的主机名
    • String getHostAddress(); // 获取这个 InetAddress实例的IP地址

代码演示:

package edu.hebeu.ip;import java.net.InetAddress;import java.net.UnknownHostException;public class InetAddressStu {
public static void main(String[] args) {
try {
InetAddress inetAddress = InetAddress.getByName("127.0.0.1"); // 获取IP为 127.0.0.1 的主机的IP对象 InetAddress inetAddress2 = InetAddress.getByName("tyong-top.design"); // 获取域名为 tyong-top.design 的主机的IP对象 InetAddress inetAddress3 = InetAddress.getLocalHost(); // 获取本地主机的IP对象 System.out.println("inetAddress: " + inetAddress.getHostName() + ", " + inetAddress.getHostAddress()); // 获取这个IP对象的注解名和IP地址 System.out.println("inetAddress2: " + inetAddress2.getHostName() + ", " + inetAddress2.getHostAddress()); // 获取这个IP对象的注解名和IP地址 System.out.println("inetAddress3: " + inetAddress3.getHostName() + ", " + inetAddress3.getHostAddress()); // 获取这个IP对象的注解名和IP地址 } catch (UnknownHostException e) {
// TODO Auto-generated catch block e.printStackTrace(); } }}

URL

Java对url是封装在URL类中的,其内部的方法比较简单,这里我就直接代码演示(代码中有详细的注解,比直接介绍API更让人容易接收),具体代码如下:

public class URL1 {
public static void main(String[] args) {
try {
URL url = new URL("https://www.bilibili.com:9999/video/BV1Kb411W75N?p=629&spm_id_from=pageDriver"); // public String getProtocol(); // 获取URL实例对象的协议名 System.out.println("协议名:" + url.getProtocol()); // public String getHost(); // 获取URL实例对象的主机名 System.out.println("主机名:" + url.getHost()); // public String getPort(); // 获取URL实例对象的端口号 System.out.println("端口号:" + url.getPort()); // public String getPath(); // 获取URL实例对象的文件路径 System.out.println("文件路径:" + url.getPath()); // public String getFile(); // 获取URL实例对象的文件名 System.out.println("文件名:" + url.getFile()); // public String getQuery(); // 获取URL实例对象的查询名 System.out.println("查询名:" + url.getQuery()); } catch (MalformedURLException e) {
// TODO Auto-generated catch block e.printStackTrace(); } }}

TCP

引用百度百科的一句话:TCP 传输协议:TCP 协议是一TCP (Transmission Control Protocol),属于传输层协议,TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送简单来说,TCP协议就是在传输信息之前要建立通道(三次握手),在结束时需要将通道关闭(四次挥手),在Java中使用Socket类和ServerSocket类来实现TCP通信,这里就不在繁琐的介绍API了(没有几个新方法,只是配合前面的几个类以及I/O流实现),直接上代码,首先我们为了测试方便,先导入junit测试包,代码实现如下:

package edu.hebeu.tcp;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.UnknownHostException;import org.junit.Test;public class TCP1 {
/** * 这个方法模仿一个客户端 */ @Test public void client() {
Socket socket = null; OutputStream outputStream = null; try {
InetAddress inetAddress = InetAddress.getByName("127.0.0.1"); // 创建要进行通信的主机的IP socket = new Socket(inetAddress, 8899); // 根据IP地址和端口号创建Socket实例 outputStream = socket.getOutputStream(); // 通过Socket实例获取一个输出流 outputStream.write("我是客户端client,我需要给你发送数据".getBytes()); } catch (UnknownHostException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } finally {
// 最后关闭资源 if(outputStream != null) {
try {
outputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(socket != null) {
try {
socket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } } } /** * 这个方法模仿一个服务端 */ @Test public void server() {
ServerSocket serverSocket = null; // 可以理解为声明一个服务端Socket Socket socket = null; // 这个Socket实例用来和ServerSocket实例配合实现接收来自客户端的信息 InputStream inputStream = null; ByteArrayOutputStream baos = null; // 这个流底层是一个会自动扩容的字节数组,将接收的字节会先存放,待接收完成后将字节数组一起进行转换(因此这个流处理中文或其他文字时绝对不会出现乱码) try {
serverSocket = new ServerSocket(8899); // 创建一个服务端,指明自己的端口号 socket = serverSocket.accept(); // 用来接收客户端的信息 inputStream = socket.getInputStream(); // 获取客户端发来的信息流 System.out.println("获取来自服务端" + socket.getInetAddress() + "的信息:"); baos = new ByteArrayOutputStream(); int readCount; byte[] bytes = new byte[3]; while((readCount = inputStream.read(bytes)) != -1) {
baos.write(bytes, 0, readCount); } System.out.println(baos.toString()); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } finally {
// 最后关闭资源 if(baos != null) {
try {
baos.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(inputStream != null) {
try {
inputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(socket != null) {
try {
socket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(serverSocket != null) {
try {
serverSocket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } } }}

测试:先启动服务端的单元测试<server()方法>,在启动客户端的单元测试<client()方法>,结果展示:

在这里插入图片描述
上面的TCP实例展示了如何实现消息的传递,那如何实现文件的传输呢?基本原理和上面的差不多,只是需要使用File类进行文件的接收就行了,具体代码如下展示:

package edu.hebeu.tcp;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.UnknownHostException;import org.junit.Test;public class TCP2 {
/** * 这个方法模仿一个客户端 */ @Test public void client() {
Socket socket = null; OutputStream outputStream = null; FileInputStream fis = null; try {
// 1、通过要通信的主机的IP和端口将来Socket实例 socket = new Socket(InetAddress.getByName("127.0.0.1"), 3000); // 2、通过Socket实例获取一个OutputStream实例 outputStream = socket.getOutputStream(); // 3、通过文件实例创建一个FileInputStream实例 fis = new FileInputStream(new File("data/client/demo.jpg")); // 4、将fis流写入到OutputStream实例中,每次最多写入1024个字节 byte[] bufferBytes = new byte[1024]; int readCount; while((readCount = fis.read(bufferBytes)) != -1) {
outputStream.write(bufferBytes, 0, readCount); } } catch (UnknownHostException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } finally {
if(fis!= null) {
try {
fis.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(outputStream != null) {
try {
outputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(socket != null) {
try {
socket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } } } /** * 这个方法模仿一个服务端 */ @Test public void server() {
ServerSocket serverSocket = null; Socket socket = null; InputStream inputStream = null; FileOutputStream fos = null; try {
// 1、创建一个ServerSocket实例 serverSocket = new ServerSocket(3000); // 2、通过ServerSocket实例获取一个Socket实例 socket = serverSocket.accept(); // 接收客户端发来的信息 System.out.println("S:接收到来自" + socket.getInetAddress() + "的资源,正在接收..."); // 3、通过Socket实例获取一个InputStream实例 inputStream = socket.getInputStream(); // 4、创建一个FileOutputStream实例,用于接收保存客户端发来的文件 fos = new FileOutputStream(new File("data/server/get.jpg")); // 5、进行接收保存 byte[] bufferBytes = new byte[1024]; int readCount; while((readCount = inputStream.read(bufferBytes)) != -1) {
fos.write(bufferBytes, 0, readCount); } System.out.println("S:接收完成!"); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } finally {
if(fos != null) {
try {
fos.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(inputStream != null) {
try {
inputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(socket != null) {
try {
socket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(serverSocket != null) {
try {
serverSocket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } } }}

测试,操作步骤通过上面一样,但是注意先创建路径保持和代码中的路径一样即可(这里是在工程下创建),准备一个文件

选择该类型的文件夹
命名为data,并在该文件夹下创建``两个目录,并且在client文件夹内放入要传输的文件(保证和上述代码的目录一致即可),如下所示:
在这里插入图片描述
运行结果:
在这里插入图片描述在这里插入图片描述
上面的例子展示了如何通过自定义的客户端、服务端传输图片,那能否在服务器接收成果图片后给客户端响应信息?其实还是换汤不换药的,我们来编写代码,如下:

package edu.hebeu.tcp;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.PrintStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.UnknownHostException;import org.junit.Test;public class TCP3 {
@Test public void client() {
PrintStream ps = null; Socket socket = null; OutputStream outputStream = null; FileInputStream fis = null; ByteArrayOutputStream baos = null; InputStream inputStream = null; try {
ps = new PrintStream(new FileOutputStream("data\\log", true)); // 将此输出流的方向改变至 data\\printData\\log 文件,并且不会覆盖原先文件的内容,不在指向控制台 System.setOut(ps); // 通过上面的对象修改输出方向,将此输出流的方向改变至 data\\printData\\log 文件,不在指向控制台 // 1、通过要通信的主机的IP和端口将来Socket实例 socket = new Socket(InetAddress.getByName("127.0.0.1"), 3000); // 2、通过Socket实例获取一个OutputStream实例 outputStream = socket.getOutputStream(); // 3、通过文件实例创建一个FileInputStream实例 fis = new FileInputStream(new File("data/client/demo.jpg")); // 4、将fis流写入到OutputStream实例中,每次最多写入1024个字节 byte[] bufferBytes = new byte[1024]; int readCount; System.out.println("C:正在发送资源..."); while((readCount = fis.read(bufferBytes)) != -1) {
outputStream.write(bufferBytes, 0, readCount); } // 5、关闭数据的输出 socket.shutdownOutput(); // 6、接收来自服务端的响应数据 inputStream = socket.getInputStream(); baos = new ByteArrayOutputStream(); byte[] bufferBytes2 = new byte[1024]; int readCount2; while((readCount2 = inputStream.read(bufferBytes2)) != -1) {
baos.write(bufferBytes2, 0, readCount2); } System.out.println("C:接收到服务端响应信息:" + baos.toString()); } catch (UnknownHostException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } finally {
System.out.println("C:正在关闭资源..."); if(baos != null) {
try {
baos.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(inputStream != null) {
try {
inputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(fis!= null) {
try {
fis.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(outputStream != null) {
try {
outputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(socket != null) {
try {
socket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(ps != null) {
ps.close(); } } } /** * 这个方法模仿一个服务端 */ @Test public void server() {
PrintStream ps = null; ServerSocket serverSocket = null; Socket socket = null; InputStream inputStream = null; OutputStream outputStream = null; FileOutputStream fos = null; try {
ps = new PrintStream(new FileOutputStream("data\\log", true)); // 将此输出流的方向改变至 data\\printData\\log 文件,并且不会覆盖原先文件的内容,不在指向控制台 System.setOut(ps); // 通过上面的对象修改输出方向,将此输出流的方向改变至 data\\printData\\log 文件,不在指向控制台 // 1、创建一个ServerSocket实例 serverSocket = new ServerSocket(3000); // 2、通过ServerSocket实例获取一个Socket实例 socket = serverSocket.accept(); // 接收客户端发来的信息 System.out.println("\nS:接收到来自" + socket.getInetAddress() + "的资源,正在接收..."); // 3、通过Socket实例获取一个InputStream实例 inputStream = socket.getInputStream(); // 4、创建一个FileOutputStream实例,用于接收保存客户端发来的文件 fos = new FileOutputStream(new File("data/server/get3.jpg")); // 5、进行接收保存 byte[] bufferBytes = new byte[1024]; int readCount; while((readCount = inputStream.read(bufferBytes)) != -1) {
fos.write(bufferBytes, 0, readCount); } System.out.println("S:接收成功!"); // 6、向客户端发送信息 outputStream = socket.getOutputStream(); outputStream.write("SUCCESS".getBytes()); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } finally {
System.out.println("S:正在关闭资源..."); if(fos != null) {
try {
fos.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(inputStream != null) {
try {
inputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(outputStream != null) {
try {
outputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(socket != null) {
try {
socket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(serverSocket != null) {
try {
serverSocket.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } } if(ps != null) {
ps.close(); } } } }

准备与上述代码保持一致的文件路径,参考上个例子,运行结果如下:

运行结果
log文件内的信息如下:
log文件内的信息

UDP

UDP(用户数据报协议)是一个简单的面向数据报的传输层协议。提供的是非面向连接的、不可靠的数据流传输。UDP不提供可靠性,也不提供报文到达确认、排序以及流量控制等功能。它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。因此报文可能会丢失、重复以及乱序等。但由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

简而言之:UDP不需要向TCP那样又是握手,又是挥手,而是直接就将数据分发成多个数据包发送出去,其不会管是否接收成功,只是保证"我发出去了,有没有接不接收没我的事",所以该方式发送的数据可能会出现丢包的情况!;
Java对该方式的使用是通过DatagramSocketDatagramPacket类来实现的,操作和TCP中的Socket类差不多(比它还要简单),这里直接上代码,不做过多的直白复述API(无一例外的都是通过IP、端口、I/O流配合实现的),具体代码如下:

package edu.hebeu.udp;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.SocketException;import java.net.UnknownHostException;import org.junit.Test;public class UDP1 {
/** * 客户端 */ @Test public void client() {
DatagramSocket ds = null; try {
ds = new DatagramSocket(); byte[] data = "我是通过UID方式发送的字符串".getBytes(); // 准备要发送的数据,将其转换为字节数组 InetAddress targetAddress = InetAddress.getByName("127.0.0.1"); // 要发送到的目标地址 DatagramPacket dp = new DatagramPacket(data, 0, data.length, targetAddress, 8899); // 创建数据包 ds.send(dp); // 发送数据包 } catch (SocketException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (UnknownHostException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } finally {
if(ds != null) {
ds.close(); } } } /** * 服务端 */ @Test public void server() {
DatagramSocket ds = null; try {
ds = new DatagramSocket(8899); byte[] buffer = new byte[1000]; DatagramPacket dp = new DatagramPacket(buffer, 0, buffer.length); // 创建数据包对象 ds.receive(dp); // 接收数据包 System.out.println(new String(dp.getData(), 0, dp.getLength())); } catch (SocketException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } finally {
if(ds != null) {
ds.close(); } } }}

测试结果:

UDP方式的测试结果
UDP方式传输文件和TCP基本是一致的,只是使用的封装类变了,其他逻辑可以参考TCP进行实现;
最后再附上百度百科中对TCP和UDP的异同总结:

TCP UDP
是否连接 面向连接 无连接
传输可靠性 可靠的 不可靠的
应用场景 传输少量数据 大量数据
速度

至此,我的笔记部分就介绍完了,当然Java的网络编程也绝不仅仅只有此部分内容,希望各位读者要保持学无止境的心态去继续学习!

转载地址:https://blog.csdn.net/m0_49039508/article/details/116243413 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:NIO的笔记总结
下一篇:javaSE学习笔记

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月28日 22时26分49秒