文章目录
- 二十九.网络编程
- 29.1 概述
- 29.2 InetAddress
- 29.3 UDP通信
- 29.3.1 UDP通信发送数据
- 29.3.2 UDP通信接收数据
- 29.3.3 Test
- 29.4 UDP的三种通信方式
- 29.4.1 单播
- 29.4.2 组播
- 29.4.3 广播
- 29.5 TCP通信
- 29.6 TCP通信三次握手
- 29.7 TCP通信四次挥手
- 29.8 Test
- 29.8.1 多次发送
二十九.网络编程
29.1 概述
网络编程三要素
- IP:设备在网络中的地址,是唯一标识的
- 端口号:应用程序在设备中的唯一标识(0-65535)
- 协议:数据在网络中传输的规则(UDP、TCP、http…)
29.2 InetAddress
static InetAddress getByName(String host)
确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
String getHostName() 获取此IP地址的主机名
String getHostAddress() 返回文本显示中的IP地址字符串
(遇见异常直接抛,默认采用alt+enter提示的第一种方式处理异常)
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Test01 {
public static void main(String[] args) throws UnknownHostException {
InetAddress mykwh = InetAddress.getByName("mykwh");
System.out.println(mykwh);//mykwh/169.254.146.8
String hostAddress = mykwh.getHostAddress();
System.out.println(hostAddress);//169.254.146.8
String hostName = mykwh.getHostName();
System.out.println(hostName);//mykwh
}
}
29.3 UDP通信
29.3.1 UDP通信发送数据
- 创建发送端的DatagramSocket对象
- 数据打包(DatagramPacket)
- 发送数据
- 释放资源
(遇见异常直接抛,默认采用alt+enter提示的第一种方式处理异常)
import java.io.IOException;
import java.net.*;
public class Test02 {
public static void main(String[] args) throws IOException {
// 1.创建发送端的DatagramSocket对象(相当于快递公司)
//绑定端口,以后我们就是通过这个端口往外发送
//空参:所有可用的端口中随机一个进行使用
//有参:指定端口号进行绑定
DatagramSocket ds = new DatagramSocket();
//2. 数据打包(DatagramPacket)
String str = "你好";
//2.1 把字符串变成字节数组
byte[] bytes = str.getBytes();
//向127.0.0.1的设备发送
InetAddress address = InetAddress.getByName("127.0.0.1");
//2.2发送到某目的地的端口号
int port = 10011;
//2.3 打包发送
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
// 3.发送数据
ds.send(dp);
// 4.释放资源
ds.close();
}
}
29.3.2 UDP通信接收数据
- 创建接收端的DatagramSocket对象
- 接收打包好的数据
- 解析数据包
- 释放资源
注意:必须先执行29.3.1中的发送数据代码,再执行接收数据代码
(遇见异常直接抛,默认采用alt+enter提示的第一种方式处理异常)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class ReceiveMessTest {
public static void main(String[] args) throws IOException {
// 1.创建接收端的DatagramSocket对象,
// 参数与发送端的端口号保持一致
DatagramSocket ds = new DatagramSocket(10011);
// 2.接收数据包
// 2.1 新建数组用来接收数据(相当于用一个新的箱子来装数据)
byte[] bytes = new byte[1024];
// 2.2用bytes接收收据,并且用bytes所有的空间来接收
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
// 2.3 接收
//receive方法是阻塞的
//程序执行到这一步的时候,会在这里死等
//等发送端发送消息
ds.receive(dp);
// 3.解析数据包
// 3.1 将数据包(即 bytes数组)里的数据解析到数组data
byte[] data = dp.getData();
//获取当前接收到多少字节数据
int length = dp.getLength();
// 获取发送设备的ip
InetAddress address = dp.getAddress();
// 获取发送设备的端口号
int port = dp.getPort();
System.out.println("接收的数据是:"+ new String(data,0,length));
System.out.println("接收数据是从"+address+"这个设备的"+port+"端口号发出的");
}
}
29.3.3 Test
UDP发送:输入ending时结束发送
UDP接收:因不知发送端何时停止发送,故采用死循环接收
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class SendMessTest {
public static void main(String[] args) throws IOException {
// 1.创建发送端对象
DatagramSocket ds = new DatagramSocket();
// 2.打包数据
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入要发送的数据:");
String str = sc.nextLine();
if("ending".equals(str)){
break;
}
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10011;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
// 3.发送数据
ds.send(dp);
}
// 4.释放资源
ds.close();
}
}
=====================================================
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveMessTest {
public static void main(String[] args) throws IOException {
// 1.创建接收端的DatagramSocket对象,
DatagramSocket ds = new DatagramSocket(10011);
//2. 创建接收数据的数据包
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
while (true) {
// 3.接收数据
ds.receive(dp);
// 4.解析数据包
byte[] data = dp.getData();
int port = dp.getPort();
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();
int len = dp.getLength();
// 5.打印数据
System.out.println("ip为:"+ip+",主机为:"+name+",端口号为:"+port+",的设备发送了"+ new String(data,0,len));
}
}
}
29.4 UDP的三种通信方式
单薄、组播、广播
29.4.1 单播
//单播:创建DatagramSocket对象形式
DatagramSocket ds = new DatagramSocket();
29.4.2 组播
组播地址:224.0.0.0 ~ 239.255.255.255
其中:224.0.0.0 ~ 224.0.0.255为预留的组播地址,自己用预留的组播地址。
创建MulticastSocket接收端对象
MulticastSocket ms = new MulticastSocket(10011);
public class SendMessTest {
public static void main(String[] args) throws IOException {
// 组播发送端
//1.创建MulticastSocket发送端对象
MulticastSocket ms = new MulticastSocket() ;
//2. 数据打包(DatagramPacket)
// 2.1要打包的数据,即发送的剧数据
String str = "追风赶月莫停留,平芜尽处是春山";
// 2.2 将发送的字符串数据变成字符数组
byte[] bytes = str.getBytes();
// 2.3 向这个地址的内的设备发送
InetAddress address = InetAddress.getByName("224.0.0.6");
//2.4向10011端口发送
int port = 10011;
// 2.5 打包数据,
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
// 3.调用MulticastSocket发送数据方法发送数据
ms.send(dp);
// 4.释放资源
ms.close();
}
}
======================================================
public class ReceiveMessTest01 {
public static void main(String[] args) throws IOException {
// 组播接收端1
//1. 创建MulticastSocket接收端对象
MulticastSocket ms = new MulticastSocket(10011);
// 2. 将将当前本机,添加到224.0.0.6的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.6");
ms.joinGroup(address);
// 3.接收数据包
// 3.1 新建数组用来接收数据(相当于用一个新的箱子来装数据)
byte[] bytes = new byte[1024];
// 3.2用bytes接收收据,并且用bytes所有的空间来接收
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
//4. 接收数据
ms.receive(dp);
// 5.解析数据
// 将数据包(即 bytes数组)里的数据解析到数组data
byte[] data = dp.getData();
//获取当前接收到多少字节数据
int len = dp.getLength();
// 获取发送设备的端口号
int port = dp.getPort();
// 获取发送设备的ip和名字
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();
System.out.println("ip为:" + ip +",主机名为:" + name + "的人,发送了数据:" + new String(data,0,len));
//6. 释放资源
ms.close();
}
}
======================================================
public class ReceiveMessTest02 {
public static void main(String[] args) throws IOException {
// 组播接收端2
//1. 创建MulticastSocket接收端对象
MulticastSocket ms = new MulticastSocket(10011);
// 2. 将将当前本机,添加到224.0.0.6的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.6");
ms.joinGroup(address);
// 3.接收数据包
// 3.1 新建数组用来接收数据(相当于用一个新的箱子来装数据)
byte[] bytes = new byte[1024];
// 3.2用bytes接收收据,并且用bytes所有的空间来接收
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
//4. 接收数据
ms.receive(dp);
// 5.解析数据
// 将数据包(即 bytes数组)里的数据解析到数组data
byte[] data = dp.getData();
//获取当前接收到多少字节数据
int len = dp.getLength();
// 获取发送设备的端口号
int port = dp.getPort();
// 获取发送设备的ip和名字
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();
System.out.println("ip为:" + ip +",主机名为:" + name + "的人,发送了数据:" + new String(data,0,len));
//6. 释放资源
ms.close();
}
}
29.4.3 广播
广播地址:255.255.255.255
InetAddress address = InetAddress.getByName("127.0.0.1");
将单播发送数据中的这行代码中的 127.0.0.1 改成 255.255.255.255 即可
29.5 TCP通信
- TCP 通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,但是传输速度慢;面向连接。
- 通信之前保证连接已经建立
- 通过Sock产生IO流来进行网络通信
(图片来自B站Java视频)
客户端(Socket):
-
创建客户端的Sock对象(Socket)与指定服务端连接
Socket ( String host, int port)
-
获取输出流,写出数据
OutputStream getOutputStream( )
-
释放资源
void close( )
服务器端(ServerSocket):
-
创建服务器端的Socket对象(ServerSocket)
ServerSocket(int port)
-
监听客户端连接,返回一个Socket对象
Socket accept( )
-
获取输入流,读取数据,并把数据显示在控制台
InputStream getInputStream( )
-
释放资源
void close( )
运行时要先运行服务端
//客户端,TCP协议,发送数据
public class Client {
public static void main(String[] args) throws IOException {
//TCP协议,发送数据
// 创建Socket对象(客户端)
//在创建对象的同时会连接服务端的ip:127.0.0.1
Socket socket = new Socket("127.0.0.1",10011);
// 连接成功后可从连接通道中获取(字节)输出流
OutputStream os = socket.getOutputStream();
// 写出数据,写出是字节数据
String str = "aa666";
os.write(str.getBytes());
// 释放资源
os.close();
socket.close();
//在释放资源时,底层会利用四次挥手协议断开连接,保证连接通道里面的数据已经处理完毕。
}
}
=======================================================
//服务器端, TCP协议,接收数据
public class Server {
public static void main(String[] args) throws IOException {
//TCP协议,接收数据
// 1.创建服务端的对象,绑定客户端的端口
ServerSocket ss = new ServerSocket(10011);
//2. 监听客户端的连接
//如果没有客户端连接,会死等
//如果有客户端连接,会返回客户端的连接对象
Socket socket = ss.accept();
// 3.从连接通道中获取(字节)输入流读取数据
InputStream is = socket.getInputStream();
// 利用转换流 转成字符转换输入流,保证读取中文不乱码
InputStreamReader isr = new InputStreamReader(is);
//还可可以将用缓冲流包装,用来提升读取效率
BufferedReader br = new BufferedReader(isr);
// 3.1 定义读取的字节数据
int b ;
//3.2 循环读取
while ((b =is.read()) != -1){
System.out.println((char) b);
}
// 4.释放资源
// 4.1断开跟客户端的连接
socket.close();
// 4.2相当于关闭了服务器
ss.close();
}
}
29.6 TCP通信三次握手
(图片来自B站Java视频)
29.7 TCP通信四次挥手
(图片来自B站Java视频)
29.8 Test
29.8.1 多次发送
客户端:多次发送数据
服务器:接收多次接收数据,并打印
public class Client {
public static void main(String[] args) throws IOException {
//客户端:多次发送数据
//服务器:接收多次接收数据,并打印
// 创建Socket对象并连接服务端
Socket socket = new Socket("127.0.0.1",10011);
// 获取字节输出流,写出数据
OutputStream os = socket.getOutputStream();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入您要发送的信息:");
String s = sc.nextLine();
if ("ending".equals(s)){
break;
}
os.write(s.getBytes());
}
// 释放资源
os.close();
socket.close();
}
}
===========================================
public class Server {
public static void main(String[] args) throws IOException {
//客户端:多次发送数据
//服务器:接收多次接收数据,并打印
//1.创建服务器端对象绑定10011端口
ServerSocket ss = new ServerSocket(10011);
//2.等待客户端来连接
Socket sock = ss.accept();
// 读取数据
// 字节输入流
InputStream is = sock.getInputStream();
// 转成字符输入流
InputStreamReader isr = new InputStreamReader(is);
//字符缓冲流
BufferedReader br = new BufferedReader(isr);
int b ;
while ((b= isr.read()) != -1){
System.out.print((char) b);
}
// String line;
// while ((line = br.readLine()) != null){
// System.out.println(line);
// }
//释放资源
ss.close();
}
}