IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> java - 网络编程之TCP、UDP和URL -> 正文阅读

[网络协议]java - 网络编程之TCP、UDP和URL

作者:token keyword

Java - 网络编程概述

1. 概述

  • java是Internet上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序
  • Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在Java的本级安装系统里,由JVM进行控制。
    并且Java实现了一个跨平台的网卡库,程序员面对的是一个统一的网络编程环境。

2. 网络通信要素要素1:IP地址和端口号

import org.junit.Test;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @ClassName: InetAddressTest
 * @Description: Java - 网络编程测试
 * @author: Mr.zhi
 * @version: v1.0
 * @data: 2022/3/19 17:31
 * @node:
 *          1. 在Java中使用InetAddress类表示IP
 *          2. 可以通过InetAddress.getByName("192.168.0.1"); 来获取IP地址
 *          3. 使用域名:www.baidu.com  www.sina.com
 *          4. 本级IP:loaclhost / 127.0.0.1
 *          5. 如何实例化InetAddress:
 *              5.1 getByName(String host)
 *              5.2 getLocalHost();
 *           6. 两个常用方法:getHostName() / getHostAddress() : 获取域名和Ip地址
 *
 *          7. 端口号:要求不同的进程有不同的端口号:0~65535
 *
 */
public class InetAddressTest {
    @Test
    public void InetAddressTest01() {

        try {
            // 网络IP地址获取测试1
            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);

            // 可通过 直接获取本地的IP地址
            InetAddress inet4 = InetAddress.getLocalHost();
            System.out.println(inet4);

            // getHostName() : 获取Ip地址的域名
            System.out.println(inet2[0].getHostName());

            // getHostAddress() : 获取域名的IP地址
            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代码测试

  • Server端
public void server() {
    ServerSocket ssc = null;
    Socket sc = null;
    InputStream is = null;
    ByteArrayOutputStream bios = null;
    try {
        // 1. 创建服务端Socket,必须指定端口号,否则无法创建Socket套接字
        ssc = new ServerSocket(7859);

        // 2. 接收客户端的socket
        sc = ssc.accept();

        // 3. 获取输入流
        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);
        }

        // 4. 打印数据
        if (bios.size() != 0) {
            System.out.print("服务器接收到:" + sc.getInetAddress().getHostAddress() + " 发送过来的数据: ");
            System.out.println(bios);
            bios.reset();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 5. 关闭流和套接字
        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();
            }
        }
    }
}
  • client端
public void client() {
    Socket sc = null; // 指明IP地址和端口号
    OutputStream os = null;
    try {
        // 1. 创建Socket对象,指明服务器端的IP地址和端口号
        InetAddress addr = InetAddress.getByName("127.0.0.1");
        sc = new Socket(addr, 7859);
    
        // 2. 获取一个输出流,用于输出数据
        os = sc.getOutputStream();
    
        // 3. 写出数据
        // 循环写出数据,直到输入exit
        StringBuilder stringBuilder = null;
        os.write(new String("栋梁栋梁!这里是TCP的Client客户端,收到请回复!").getBytes(StandardCharsets.UTF_8));

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 4. 关闭Socket对象
        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测试二:实现文件的复制

// note: 在实际开发中,一定要使用try-catch-finally进行异常的处理,而不是直接抛出。这里为了显示代码逻辑进行了直接抛出
@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()方法
// note: 在实际开发中,一定要使用try-catch-finally进行异常的处理,而不是直接抛出。这里为了显示代码逻辑进行了直接抛出
@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));
    // 当客户端想要接收数据时,需要告诉服务端什么时候发送完成
    // 因为read()为阻塞式的
    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;

/**
* @ClassName: UDPTest
* @Description: Java - 网络编程之UDP测试
* @author: Mr.zhi
* @version: v1.0
* @data: 2022/3/20 21:50
* @node:
*          - 类 DatagramSocket 和 DatagramPacket 实现了基于UDP协议网络程序
*          - UDP数据报通过套接字 DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
*          - DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号
*          - UDP协议中每个数据报都给出了完成的地址信息,因此无序建立发送方和接收方的连接。
*/
public class UDPTest {
@Test
// UDP的发送端
public void sender() {
DatagramSocket datagramSocket = null; // 此时可以不用指定IP地址和端口号
try {
// 1. 使用类DatagramSocket 建立UDP的套接字
datagramSocket = new DatagramSocket();

            // 2. 使用类DatagramPacket 建立UDP的数据报,来存储数据
            // 如果 datagramSocket 没有指定IP和端口号,则需要在这里进行绑定
            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);

            // 3. 调用DatagramSocket的send()方法发送数据
            datagramSocket.send(datagramPacket);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4. 关闭套接字
            if (datagramSocket != null) {
                datagramSocket.close();
            }
        }
    }

    // UDP的接收端
    @Test
    public void receiver() {
        DatagramSocket socket = null;
        try {
            // 1. 建立UDP套接字,因为是服务端,所以需要指定端口号
            socket = new DatagramSocket(8081);

            // 2. 建立数据报
            byte[] buffer = new byte[100]; // 因此使用UDP接收数据报时,需要一次性全部接收,如果接收不完则会抛弃,因此可以将该数组设置大一点
            DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);

            // 3. 调用DatagramSocket的receive()方法进行数据接收,并存放如packet中
            socket.receive(packet);

            // 4. 将数据进行打印
            System.out.println(new String(packet.getData(), 0, packet.getLength()));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 5. 关闭套接字
            socket.close();
        }


    }
}

UDP服务端的控制台输出:
UDP服务端的控制台

4.2 UDP代码测试二:可以连续发送数据

public class UDPTest {
    public static void main(String[] args) {
        UDPTest.sender();
    }

//    @Test
    // UDP的发送端
    public static void sender() {
        DatagramSocket datagramSocket = null; // 此时可以不用指定IP地址和端口号
        try {
            // 1. 使用类DatagramSocket 建立UDP的套接字
            datagramSocket = new DatagramSocket();

            // 2. 使用类DatagramPacket 建立UDP的数据报,来存储数据
            // 如果 datagramSocket 没有指定IP和端口号,则需要在这里进行绑定
            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);
                // 3. 调用DatagramSocket的send()方法发送数据
                datagramSocket.send(datagramPacket);
                if ("exit".equalsIgnoreCase(str) || "e".equalsIgnoreCase(str)) {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4. 关闭套接字
            if (datagramSocket != null) {
                datagramSocket.close();
            }
        }
    }

    // UDP的接收端
    @Test
    public void receiver() {
        DatagramSocket socket = null;
        try {
            // 1. 建立UDP套接字,因为是服务端,所以需要指定端口号
            socket = new DatagramSocket(8081);

            // 2. 建立数据报
            byte[] buffer = null; // 因此使用UDP接收数据报时,需要一次性全部接收,如果接收不完则会抛弃,因此可以将该数组设置大一点
            DatagramPacket packet = null;

            // 连续接收数据,直到收到exit或e后退出
            while (true) {
                buffer = new byte[100];
                packet = new DatagramPacket(buffer, 0, buffer.length);

                // 3. 调用DatagramSocket的receive()方法进行数据接收,并存放如packet中
                socket.receive(packet);

                // 4. 将数据进行打印
                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 {
            // 5. 关闭套接字
            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() {
  // 1. 创建URL标识
  try {
  	URL url = new URL("http://192.168.0.100:8080/helloworld/index.jsp#a?username=zhilx&passwd=123456");

  	// 2. URL常用方法测试
  	// 2.1 使用 getProtocol获取URL的协议名
  	System.out.println(url.getProtocol());

  	// 2.2 使用getHost()获取URL的主机名
  	System.out.println(url.getHost());

  	// 2.3 使用getPost()获取URL的端口号
  	System.out.println(url.getProtocol());

  	// 2.4 使用getPath()获取文件路径
  	System.out.println(url.getPath());

  	// 2.5 使用getFile()获取URL的文件名
  	System.out.println(url.getFile());

  	// 2.6 使用getQuery() 获取URL的查询名
  	System.out.println(url.getQuery());

  } catch (MalformedURLException e) {
  	e.printStackTrace();
  }
}

5.3 URL方法测试:从指定页面下载文件

// 2. URL编程实现网络资源的下载
// TCP、UDP的博客中的图片: https://img-blog.csdnimg.cn/56b8a4e4777c4b4ba632cbf9cbeaac5e.png
public void test02(){
	InputStream inputStream = null;
	FileOutputStream fos = null;
	try {
		// 1. 指定URL的指定文件位置
		URL url = new URL(" https://img-blog.csdnimg.cn/56b8a4e4777c4b4ba632cbf9cbeaac5e.png");

		// 2. 获取URL连接
		HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

		// 3. 建立连接(一定要有这个步骤)
		urlConnection.connect();

		// 4. 下载数据
		inputStream = urlConnection.getInputStream();
		fos = new FileOutputStream("7-网络编程\\src\\figure1.png");

		// 5. 将数据写入到文件中
		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 {// 6. 关闭流和套接字
		if (fos != null) {
			try {
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-22 20:58:43  更:2022-03-22 20:59:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:00:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码