Java学习笔记——网络编程

  • 网络编程的目的:

    直接或间接地通过网络协议与其它计算机进行通讯

  • 网络编程中有两个主要的问题:

    • 如何准确地定位网络上一台或多台主机(IP地址)

    • 找到主机后如何可靠高效地进行数据传输(网络通信协议:TCP/IP参考模型等)

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

本笔记主要记录java的网络编程相关的API,对通信原理细节不做深究。

1. InetAddress类

IP 地址,唯一标识 Internet 上的一台计算机。

InetAddress 类对象含有一个 Internet 主机地址的域名和IP地址,两个子类Inet4Address、Inet6Address。

InetAddress类没有提供公共的构造器,而是提供了如下几个静态方法来获取InetAddress实例。

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

import org.junit.jupiter.api.Test;

public class TestInetAddress {
	public static void main(String[] args) throws UnknownHostException {
		InetAddress inetAddress = InetAddress.getByName("www.baidu.com");
		System.out.println(inetAddress); // www.baidu.com/183.232.231.173
		System.out.println(inetAddress.getHostName()); // www.baidu.com
		System.out.println(inetAddress.getHostAddress()); // 183.232.231.173
		
		InetAddress inetAddress2 = InetAddress.getByName("183.232.231.172");
		System.out.println(inetAddress2); // /183.232.231.172
		System.out.println(inetAddress2.getHostName()); // 183.232.231.172
		System.out.println(inetAddress2.getHostAddress()); // 183.232.231.172
		
		InetAddress inetAddress3 = InetAddress.getLocalHost();
		System.out.println(inetAddress3); // DESKTOP-0CBDASS/192.168.111.1
		System.out.println(inetAddress3.getHostName()); // DESKTOP-0CBDASS
		System.out.println(inetAddress3.getHostAddress()); // 192.168.111.1
		
		String[] ipSplit = "183.232.231.172".split("\\.");
		byte[] bytes = new byte[] {(byte) Short.parseShort(ipSplit[0]), (byte) Short.parseShort(ipSplit[1]), 
				(byte) Short.parseShort(ipSplit[2]), (byte) Short.parseShort(ipSplit[3])};
		InetAddress inetAddress4 = InetAddress.getByAddress(bytes); 
		System.out.println(inetAddress4); // /183.232.231.172
		System.out.println(inetAddress4.getHostName()); // 183.232.231.172
		System.out.println(inetAddress4.getHostAddress()); // 183.232.231.172
	}
}

2. TCP网络通信

网络通信其实就是Socket间的通信。TCP的Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。

package internet;

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 org.junit.jupiter.api.Test;


public class TestTCP2 {
	@Test
	public void client() {
		Socket socket = null;
		OutputStream os = null;
		InputStream is = null;
		try {
			// 1.创建一个Socket的对象,通过构造器指明服务端的IP地址,以及其接收程序的端口号
			socket = new Socket(InetAddress.getByName("localhost"), 9090);
			// 2.getOutputStream():方法返回OutputStream的对象
			os = socket.getOutputStream();
			// 3.具体的输出过程
			os.write("来自客户端的数据".getBytes());
			socket.shutdownOutput(); // 显式的告诉服务端发送完毕
			// 4.接收来自服务端的数据
			is = socket.getInputStream();
			byte[] b = new byte[20];
			int len;
			while ((len = is.read(b)) != -1) {
				String str = new String(b, 0, len);
				System.out.print(str);
			} 
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			// 5.关闭流和socket
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (os != null) {
				try {
					os.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	@Test
	public void server() {
		ServerSocket ss = null;
		Socket socket = null;
		InputStream is = null;
		OutputStream os = null;
		
		try {
			// 1.创建一个ServerSocket的对象,通过构造器指明自身的端口号
			ss = new ServerSocket(9090);
			// 2.调用其accept()方法,返回一个Socket的对象,此时与客户端建立连接
			socket = ss.accept();
			// 3.调用Socket对象的getInputStream()获取一个从客户端发送过来的输入流
			is = socket.getInputStream();
			// 4.对获取的输入流进行的操作
			byte[] b = new byte[20];
			int len;
			while((len = is.read(b)) != -1) {
				String str = new String(b, 0, len);
				System.out.print(str);
			}
			System.out.println("接收完毕");
			// 5.向客户端发送数据
			os = socket.getOutputStream();
			os.write("来自服务端的数据:收到".getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 5.关闭相应的流以及Socket、ServerSocket的对象
			if (os != null) {
				try {
					os.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

总结:TCP的一个socket由源地址、源端口、目的地址、目的端口唯一确定,在客户端创建一个Socket对象时,需指定服务器的ip地址和端口,本身的ip地址和端口会自动生成,有了socket之后,就可以从中获取InputStream或OutputStream,以进行接收数据和发送数据的操作。由于TCP是面向连接的,在服务端要先创建一个ServerSocket对象,以”接待“所有发起连接的客户,并调用其accept方法为每个连接返回一个指定的Socket,这样每个客户在服务端就唯一对应一个Socket,并与这个Socket进行通信。

3. UDP网络通信

类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。UDP数据报通过数据报套接字DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。

package internet;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

import org.junit.jupiter.api.Test;

public class TestUDP {
	@Test
	public void send() {
		DatagramSocket ds = null;
		try {
			// 创建DatagramSocket对象
			ds = new DatagramSocket();
			// 创建DatagramPacket数据包,每一个数据报不能大于64k
			byte[] b = "来自客户端的数据".getBytes();
			DatagramPacket packet = new DatagramPacket(b, 0, b.length, InetAddress.getByName("localhost"), 9090);
			// 调用DatagramSocket的send方法发送数据包
			ds.send(packet);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 关闭DatagramSocket
			if (ds != null) {
				ds.close();
			}
		}
	}
	
	@Test
	public void receive() {
		DatagramSocket ds = null;
		try {
			// 创建DatagramSocket对象,需指明监听的端口
			ds = new DatagramSocket(9090);
			// 创建DatagramPacket数据包
			byte[] b = new byte[1024];
			DatagramPacket packet = new DatagramPacket(b, 0, b.length);
			// 调用DatagramSocket的receive方法接收数据包
			ds.receive(packet);
			String string = new String(packet.getData(), 0, packet.getLength());
			System.out.println(string);
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			// 关闭DatagramSocket
			if (ds != null) {
				ds.close();
			}
		}
	}
}

总结:在代码上体现出的UDP与TCP的最大不同,在于TCP是面向连接的,而UDP没有,所以接收端也没有一个ServerSocket,而是直接使用DatagramSocket进行通信;并且也没有流的概念,直接调用方法发送或接收数据,且数据需要先封装成DatagramPacket。

4. URL编程

URL(Uniform Resource Locator):统一资源定位符,它表示 Internet 上某一资源的地址。通过 URL 我们可以访问 Internet 上的各种网络资源,比如最常见的 www,ftp 站点。浏览器通过解析给定的 URL 可以在网络上查找相应的文件或其他资源。

URL的基本结构由5部分组成:
<传输协议>://<主机地址>:<端口号>/<文件路径>
例如: http://192.168.1.100:8080/helloworld/index.jsp

一个URL对象生成后,其属性是不能被改变的,但可以通过它给定的方法来获取这些属性:

URL url = new URL("http://hao.91nzh.com:8080/static/images/jd.jpg?a=b");

System.out.println(url.getPath()); // 路径名:/static/images/jd.jpg
System.out.println(url.getProtocol()); // 协议名:http
System.out.println(url.getHost()); // 主机名: hao.91nzh.com
System.out.println(url.getPort()); // 端口号:8080
System.out.println(url.getFile()); // 文件路径:/static/images/jd.jpg?a=b
System.out.println(url.getRef()); // 该URL在文件中的相对位置:null
System.out.println(url.getQuery()); // 查询名:a=b

URL的方法 openStream():能从网络上读取数据。

若希望输出数据,例如向服务器端的 CGI (公共网关接口-Common Gateway Interface-的简称,是用户浏览器和服务器端的应用程序进行连接的接口)程序发送一些数据,则必须先与URL建立连接,然后才能对其进行读写,此时需要使用 URLConnection 。

URL url = null;
try {
    url = new URL("http://hao.91nzh.com/static/images/jd.jpg");
    InputStream is = null;
    FileOutputStream fos = null;
    try {
        // 使用openStream()方法获取输入流,从服务端读取数据
        is = url.openStream();
        fos = new FileOutputStream("jingdong.jpg");
        byte[] b = new byte[1024];
        int len;
        while((len = is.read(b)) != -1) {
            fos.write(b, 0, len);
        }
        //如果既有数据的输入,又有数据的输出,则考虑使用URLConnection
        URLConnection urlConn = url.openConnection();
        InputStream is1 = urlConn.getInputStream();
        OutputStream os = urlConn.getOutputStream();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (fos != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        ...
    }
} catch (MalformedURLException e) {
    e.printStackTrace();
}

总结:类 URL 和 URLConnection 提供了最高级网络应用。URL 的网络资源的位置来同一表示 Internet 上各种网络资源。通过URL对象可以创建当前应用程序和 URL 表示的网络资源之间的连接,这样当前程序就可以读取网络资源数据,或者把自己的数据传送到网络上去。


相关阅读:
Java学习笔记——IO流
Java学习笔记——异常处理


以上笔记参考自尚硅谷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值