Java - 网络编程概述
1. 概述
- java是Internet上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序
- Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在Java的本级安装系统里,由JVM进行控制。
并且Java实现了一个跨平台的网卡库,程序员面对的是一个统一的网络编程环境。
2. 网络通信要素要素1:IP地址和端口号
import org.junit.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressTest {
@Test
public void InetAddressTest01() {
try {
InetAddress inet1 = InetAddress.getByName("192.168.0.1");
System.out.println(inet1);
InetAddress[] inet2 = InetAddress.getAllByName("www.baidu.com");
for (int i = 0; i < inet2.length; ++i) {
System.out.println(inet2[i]);
}
InetAddress inet3 = InetAddress.getByName("127.0.0.1");
System.out.println(inet3);
InetAddress inet4 = InetAddress.getLocalHost();
System.out.println(inet4);
System.out.println(inet2[0].getHostName());
System.out.println(inet4.getHostName());
System.out.println(inet4.getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
3. 通信要素2:网络协议
3.1 TCP
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
- 传输前,采用“三次握手”方式,点对点通信,是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务器
- 在连接中可进行大数据量的传输
- 传输完毕后,需释放已建立的连接,效率低
3.2 UDP
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64K内
- 发送不管对方会是否准备好,接收方收到也不确认,故为不可靠的
- 可以广播发送
- 发送数据结束时无序释放资源,开销小,速度快
3.3 TCP代码测试
public void server() {
ServerSocket ssc = null;
Socket sc = null;
InputStream is = null;
ByteArrayOutputStream bios = null;
try {
ssc = new ServerSocket(7859);
sc = ssc.accept();
is = sc.getInputStream();
bios = new ByteArrayOutputStream();
byte[] buffer = new byte[100];
int len = -1;
while ((len = is.read(buffer)) != -1) {
bios.write(buffer, 0, len);
}
if (bios.size() != 0) {
System.out.print("服务器接收到:" + sc.getInetAddress().getHostAddress() + " 发送过来的数据: ");
System.out.println(bios);
bios.reset();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bios != null) {
try {
bios.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (sc != null) {
try {
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ssc != null) {
try {
ssc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void client() {
Socket sc = null;
OutputStream os = null;
try {
InetAddress addr = InetAddress.getByName("127.0.0.1");
sc = new Socket(addr, 7859);
os = sc.getOutputStream();
StringBuilder stringBuilder = null;
os.write(new String("栋梁栋梁!这里是TCP的Client客户端,收到请回复!").getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (sc != null) {
try {
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.4 TCP测试二:实现文件的复制
@Test
public void client() throws IOException {
Socket sc = new Socket( InetAddress.getByName("127.0.0.1"), 8001);
OutputStream outputStream = sc.getOutputStream();
FileInputStream fis = new FileInputStream("photo.jpg");
byte[] data = new byte[1024];
int len = -1;
while ((len = fis.read(data)) != -1) {
outputStream.write(data,0, len);
}
System.out.println("文件复制完成");
fis.close();
outputStream.close();
sc.close();
}
@Test
public void server() throws IOException {
ServerSocket serverSocketc = new ServerSocket(8001);
Socket socket = serverSocketc.accept();
InputStream inputStream = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("photo2.jpg");
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("文件复制完成");
fos.close();
inputStream.close();
socket.close();
serverSocketc.close();
}
3.5 TCP测试三:当服务端收到通知后回复客户端
- note: 需要注意的是,因为read()为阻塞式的,因此服务端需要知道客户端什么时候发送结束。
- 因此在客户端需要使用socket.shutdownOutput()方法
@Test
public void client() throws IOException {
Socket sc = new Socket( InetAddress.getByName("127.0.0.1"), 8001);
OutputStream outputStream = sc.getOutputStream();
outputStream.write("栋梁栋梁!这里是Clinet客户端,收到请回复!".getBytes(StandardCharsets.UTF_8));
sc.shutdownOutput();
InputStream inputStream = sc.getInputStream();
byte[] buffer = new byte[1024];
int len = -1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
System.out.println(baos.toString());
baos.close();
inputStream.close();
outputStream.close();
sc.close();
}
@Test
public void server() throws IOException {
ServerSocket serverSocketc = new ServerSocket(8001);
Socket socket = serverSocketc.accept();
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = -1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
System.out.println(baos);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("收到回复!".getBytes(StandardCharsets.UTF_8));
System.out.println("已回复");
outputStream.close();
inputStream.close();
socket.close();
serverSocketc.close();
}
结果: TCP服务端: TCP客户端:
4. UDP 网络通信测试
- 类 DatagramSocket 和 DatagramPacket 实现了基于UDP协议网络程序
- UDP数据报通过套接字 DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
- DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号
- UDP协议中每个数据报都给出了完成的地址信息,因此无序建立发送方和接收方的连接。
4.1 UDP代码测试一:
import org.junit.Test;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
public class UDPTest {
@Test
public void sender() {
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket();
String str = new String("Hello, 这是使用UDP发送的数据报!");
byte[] data = str.getBytes(StandardCharsets.UTF_8);
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
DatagramPacket datagramPacket = new DatagramPacket(data, 0, data.length, inetAddress, 8081);
datagramSocket.send(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
@Test
public void receiver() {
DatagramSocket socket = null;
try {
socket = new DatagramSocket(8081);
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
System.out.println(new String(packet.getData(), 0, packet.getLength()));
} catch (IOException e) {
e.printStackTrace();
} finally {
socket.close();
}
}
}
UDP服务端的控制台输出:
4.2 UDP代码测试二:可以连续发送数据
public class UDPTest {
public static void main(String[] args) {
UDPTest.sender();
}
public static void sender() {
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket();
String str = new String("Hello, 这是使用UDP发送的数据报!");
byte[] data = str.getBytes(StandardCharsets.UTF_8);
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
DatagramPacket datagramPacket = null;
datagramPacket = new DatagramPacket(data, 0, data.length, inetAddress, 8081);
datagramSocket.send(datagramPacket);
while (true) {
str = new String(new Scanner(System.in).nextLine());
data = str.getBytes(StandardCharsets.UTF_8);
datagramPacket = new DatagramPacket(data, 0, data.length, inetAddress, 8081);
System.out.println(str);
datagramSocket.send(datagramPacket);
if ("exit".equalsIgnoreCase(str) || "e".equalsIgnoreCase(str)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
@Test
public void receiver() {
DatagramSocket socket = null;
try {
socket = new DatagramSocket(8081);
byte[] buffer = null;
DatagramPacket packet = null;
while (true) {
buffer = new byte[100];
packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
String str = new String(new String(packet.getData(), 0, packet.getLength()));
if ("exit".equalsIgnoreCase(str) || "e".equalsIgnoreCase(str)) {
break;
}
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
socket.close();
}
}
}
5. URL 编程
5.1 URL概述
- URL(Uniform Resource Locator) : 统一资源定位符,它表示Internet上某一资源的地址
- 它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何loacte这个资源。
- 通过URL我们可以访问Internet上的各种网络资源,比如最常见的www, ftp站点。
浏览通过解析给定的URL可以在网络上查找相应的文件或其他资源。 - URL的基本结构由5部分组成:
- <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
- 例如:
http://192.168.0.100:8080/helloworld/index.jsp#a?username=zhilx&passwd=123456 - #片段名:即锚点,例如看小说,直接定位到章节
- 参数列表格式:参数名=参数值&参数名=参数值…
5.2 URL常用方法代码测试:
public void test01() {
try {
URL url = new URL("http://192.168.0.100:8080/helloworld/index.jsp#a?username=zhilx&passwd=123456");
System.out.println(url.getProtocol());
System.out.println(url.getHost());
System.out.println(url.getProtocol());
System.out.println(url.getPath());
System.out.println(url.getFile());
System.out.println(url.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
5.3 URL方法测试:从指定页面下载文件
public void test02(){
InputStream inputStream = null;
FileOutputStream fos = null;
try {
URL url = new URL(" https://img-blog.csdnimg.cn/56b8a4e4777c4b4ba632cbf9cbeaac5e.png");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
inputStream = urlConnection.getInputStream();
fos = new FileOutputStream("7-网络编程\\src\\figure1.png");
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("文件下载完成!");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|