Java网络编程的笔记小结

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的异同总结:

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

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值