Skip to content

Java网络编程

2598字约9分钟

java网络编程socket

2024-10-24

1.传输层协议

TCP

UDP

上层应用:URL、URL Encode、URL Decode

2.IP地址

1.标志网络设备的唯一标志

2.一台网络设备是可以有多个IP地址的

3.一个IP地址只能对应一个网络设备

3.IP地址的分类

长度

ipv4

4字节,32位

IPv4地址由四段组成,每个字段是一个字节,8位,最大值是255,,

IPv4地址由两部分组成,即网络地址和主机地址。网络地址表示其属于互联网的哪一个网络,主机地址表示其属于该网络中的哪一台主机,二者是主从关系。

IPv4地址的四大类型标识的是网络中的某台主机。IPv4地址长度为32位,共4个字节,但实际中我们用点分十进制记法

IPv4地址根据网络号和主机号来分,分为A、B、C三类及特殊地址D、E。全0和全1的都保留不用,如A类中的0.0.0.0和127.255.255.255都不使用。

img

A类:(1.0.0.1-126.255.255.254)(默认子网掩码:255.0.0.0或0xFF000000)第一个字节为网络号,后三个字节为主机号,表示为网络--主机--主机--主机。该类IP地址的最前面为“0”,所以地址的网络号取值于1~126之间。共有16777214个主机地址,一般用于大型网络。

B类:(128.1.0.1-191.254.255.254)(默认子网掩码:255.255.0.0或0xFFFF0000)前两个字节为网络号,后两个字节为主机号。该类IP地址的最前面为“10”,所以地址的网络号取值于128~191之间。共有65534个主机地址,一般用于中等规模网络。

C类:(192.0.1.1-223.255.254.254)(子网掩码:255.255.255.0或0xFFFFFF00)前三个字节为网络号,最后一个字节为主机号。该类IP地址的最前面为“110”,所以地址的网络号取值于192~223之间。共有254个主机地址,一般用于小型网络。

D类:是多播地址。(224.0.0.1-239.255.255.254) 该类IP地址的前面4位为“1110”,所以网络号取值于224~239之间;后面28位为组播地址ID。这是一个专门保留的地址。它并不指向特定的网络,目前这一类地址被用在多点广播(Multicasting)中。多点广播地址用来一次寻址一组计算机,它标识共享同一协议的一组计算机。

E类:是保留地址,为将来使用保留。(240.0.0.0---255.255.255.254) 该类IP地址的最前面为“1111”,所以网络号取值于240~255之间。

注意:所有的网络空间计算都必须 -2,这是因为要扣除两个保留地址:

主机号全部为1的地址是子网广播地址,如:192.168.1.255 ;

主机号全部为0的地址是代表该子网的网络地址,如:192.168.1.0 ;

1-254才是给主机使用的。

ipv6

IPv6是英文“Internet Protocol Version 6”(互联网协议第6版)的缩写,是互联网工程任务组(IETF)设计的用于替代IPv4的下一代IP协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址

互联网数字分配机构(IANA)在2016年已向国际互联网工程任务组(IETF)提出建议,要求新制定的国际互联网标准只支持IPv6,不再兼容IPv4。

IP v6与v4区别?

1.地址长度 IPv4协议具有32位(4字节)地址长度;IPv6协议具有128位(16字节)地址长度

地址的表示方法 IPv4地址是以点分割的十进制表示的二进制数。 IPv6地址是以十六进制表示的二进制数。

2.地址配置 IPv4协议的地址可以通过手动或DHCP配置的。 IPv6协议需要使用Internet控制消息协议版本6(ICMPv6)或DHCPv6的无状态地址自动配置(SLAAC)。

3.包的大小 IPv4协议的数据包需要576个字节,碎片可选 。IPv6协议的数据包需要1280个字节,不会碎片

4.包头 IPv4协议的包头的长度为20个字节,不识别用于QoS处理的数据包流,包含checksum,包含最多40个字节的选项字段。

5.IPv6协议的包头的长度为40个字节,包含指定QoS处理的数据包流的Flow Label字段,不包含checksum;IPv6协议没有字段,但IPv6扩展标头可用。

6.地址解析协议 IPv4协议:地址解析协议(ARP)可用于将IPv4地址映射到MAC地址。IPv6协议:地址解析协议(ARP)被邻居发现协议(NDP)的功能所取代。

7.身份验证和加密 IPv6提供身份验证和加密,但IPv4不提供。

4.传输层

保证数据可靠顺序送达

端口:端口号主要运用于传输层上,用来标识同一台计算机中进行通信的不同应用程序(进程)。因此也被成为应用程序地址。

根据端口号识别应用(程序)

TCP的端口和UDP的端口是分开的

TCP 最多有 65536个端口,UDP最多有 65536个端口

0-1024 系统留用

1024-49151 自己定义使用的端口

49152~65535 动态端口

TCP21端口:FTP文件传输服务 TCP23端口:TELNET终端仿真服务 TCP25端口:SMTP简单邮件传输服务 UDP53端口:DNS域名解析服务 TCP80端口:HTTP超文本传输服务 TCP110端口:POP3“邮局协议版本3”使用的端口 TCP443端口:HTTPS加密的超文本传输服务 TCP1521端口:Oracle数据库服务

TCP3306端口:MySQL 数据库服务

TCP8080端口:Tomcat默认使用的端口

5.java进行TCP通信

1.Socket通信(套接字、类似网络管道)

对于网络应用程序,一定分为客户端和服务端2部分

在进行通信过程中,一定要先启动服务端。

进行端口监听。

image-20211015094332974

代码

image-20211015103533742

TCP通信

/**
 *服务端
 **/
 public class TcpServer {
	public static void main(String[] args) {
		try {
			// 建立ServerSocket对象
			ServerSocket serverSocket = new ServerSocket(8888);
			// 建立服务端Socket对象
			System.out.println("服务端监听中....");
			Socket socket = serverSocket.accept();
			System.out.println("客户端已连接");
			// 获取服务端socket对象的输入流
			InputStream inputStream = socket.getInputStream();
			// 获取服务端socket对象的输出流
			OutputStream outputStream = socket.getOutputStream();
			// 使用数据流给客户端发送一个字符串
			DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
			dataOutputStream.writeUTF("我是服务端");
			// 使用数据流获取客户端发来的数据
			DataInputStream dataInputStream = new DataInputStream(inputStream);
			System.out.println(dataInputStream.readUTF());
			socket.close();
			serverSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
/**
 *客户端
 **/
public class TcpClient {
	public static void main(String[] args) {
		try {
			// 建立客户端socket对象
			Socket socket = new Socket("127.0.0.1", 8888);
			// 获取客户端socke对象的输入流
			InputStream inputStream = socket.getInputStream();
			// 获取客户端socket对象的输出流
			OutputStream outputStream = socket.getOutputStream();
			// 使用数据流获取服务端发来的数据
			DataInputStream dataInputStream = new DataInputStream(inputStream);
			System.out.println(dataInputStream.readUTF());
			// 使用数据流给服务端发送数据
			DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
			dataOutputStream.writeUTF("收到服务端发送的数据");
			System.out.println("收到服务端发送的数据");
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

UDP通信

/**
 *服务端
 **/
public class UdpServer {
	public static void main(String[] args) {
		try {
			// 创建一个数据报socket对象
			DatagramSocket datagramSocket = new DatagramSocket(9999);
			System.out.println("wait....");
			byte[] buf = new byte[1024];
			// 创建一个数据包对象
			DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
			// 创建一个字节数组输入流
			ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(buf);
			// 创建一个字节数组输出流
			ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
			datagramSocket.receive(datagramPacket);
			// 服务端接受客户端的数据
			DataInputStream dataInputStream = new DataInputStream(arrayInputStream);
			System.out.println(dataInputStream.readUTF());
			System.out.println("服务端接受成功");
			DataOutputStream dataOutputStream = new DataOutputStream(arrayOutputStream);
			dataOutputStream.writeUTF("我是服务端发送的数据");
			byte[] buff = arrayOutputStream.toByteArray();
			datagramSocket.send(new DatagramPacket(buff, buff.length,InetAddress.getByName("127.0.0.1"),9999));
		}
 catch (SocketException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
/**
 *客户端
 **/
public class UdpClient {
	public static void main(String[] args) {
		try {
			// 创建一个无连接的datagramSocket对象
			DatagramSocket datagramSocket = new DatagramSocket();
			// 使用数据流写入
			ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(9999);
			DataOutputStream dataOutputStream = new DataOutputStream(arrayOutputStream);
			dataOutputStream.writeUTF("我是客户端发送的数据");
			byte[] buf = null;
			buf = arrayOutputStream.toByteArray();
			DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"),9999);
			// 客户端发送数据
			datagramSocket.send(datagramPacket);
			System.out.println("客户端发送成功");
			byte[] buff = new byte[1024];
 			ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(buff);
			DataInputStream dataInputStream = new DataInputStream(arrayInputStream);
			System.out.println(dataInputStream.readUTF());
			datagramSocket.close();
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

2.TCP与UDP的区别

1.都是传输层协议

2.TCP的基于可连接的协议的

2.1建立连接 三次握手协议 建立虚电路

2.2断开连接 四次挥手协议 断开虚电路

3.UDP基于无连接的通信,以恒定的时间发送数据

可单播、多播、广播、不可靠、无拥塞控制

4.TCP类似打电话,UDP类似发短信

5.TCP需要维护长连接(一般通过发送心跳包保持长连接(周期位斐波那契数列))’

6.UDP由于没有握手协议,效率略高

这里写图片描述

3.BIO,NIO,AIO的区别?

BIO 在JDK1.4出来之前就有的阻塞的Block IO。

NIO 同步非阻塞的NIO

AIO 异步IO 异步非阻塞的AIO。

Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。 Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理, NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。 AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持 I/O属于底层操作,需要操作系统支持,并发也需要操作系统的支持,所以性能方面不同操作系统差异会比较明显。另外NIO的非阻塞,需要一直轮询,也是一个比较耗资源的。所以出现AIO