InetAddress类
相关方法
- 获取本机InetAddress 对象 getLoacalHost
- 根据指定主机名/域名获取 ip 地址对象 getByName
- 获取InetAddress对象的主机名 getHostName
- 获取InetAddress对象的地址 getHostAddress
案例
//获取本机 InetAddress 对象 getLocalHost
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
//根据指定主机名/域名获取 ip 地址对象 getByName
InetAddress host2 = InetAddress.getByName("ThinkPad-PC");
System.out.println(host2);
InetAddress host3 = InetAddress.getByName("www.hsp.com");
System.out.println(host3);
//获取 InetAddress 对象的主机名 getHostName
String host3Name = host3.getHostName();
System.out.println(host3Name);
//获取 InetAddress 对象的地址 getHostAddress
String host3Address = host3.getHostAddress();
System.out.println(host3Address);
Socket
基本介绍
- 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准。
- 通信的两端都要有Socket,是两台机器间通信的端点
- 网络通信其实就是Socket间的通信
- Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
- 一般主动发起通信的应用程序属于客户端,等待通信请求的为服务端。
TCP网络编程
基本介绍
- 基于客户端——服务端的网络通信
- 底层使用的是TCP/IP协议
- 应用场景举例:客户端发送数据,服务端接受并现实控制台
- 基于Socket的TCP编程
案例
案例1 —— 使用字节流
- 编写一个服务器端,和一个客户端
- 服务器端在 9999端口监听
- 客户端连接到服务器端,发送 "hello , server " ,然后退出
- 服务器端接受到 客户端发送的 信息,输出,并退出
server.java
public class server1 {
public static void main(String[] args) throws IOException {
//1. 在本机的 9999端口监听,等待连接
// 前提:要求在本机没有其他服务在监听9999
// serversocket 可以通过 accept() 方法 返回多个Socket[多个客户端连接服务端]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接");
//2.当没有客户端连接9999端口时,程序会 阻塞, 等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("socket="+ socket.getClass());
// 3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据,显示
InputStream inputStream = socket.getInputStream();
//4.IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while((readLen=inputStream.read(buf))!=-1){
System.out.println(new String(buf,0,readLen));
}
//5.关闭流和socket
inputStream.close();
socket.close();
serverSocket.close();
}
}
client.java
public class client1 {
public static void main(String[] args) throws IOException {
//1 . 连接服务器 (ip,端口)
//连接本机的9999端口
Socket socket = new Socket(Inet6Address.getLocalHost(), 9999);
System.out.println("客户端 socket返回 ="+ socket.getClass());
//2.连接上后,生成socket,通过socket.getOutputStream()
//得到 和 socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3. 通过输出流 , 写入数据到 数据通道
outputStream.write("hello,server".getBytes());
//4.关闭流对象和socket , 必须关闭
outputStream.close();
socket.close();
System.out.println("客户端退出");
}
}
案例2 —— 使用字节流2
- 编写一个服务器,和一个客户端
- 服务器端在 9999 端口监听
- 客户端连接到服务端,发送 “hello,server" , 并接受服务器端回发的 ”hello,client“,再退出
- 服务器端接收到 客户端发送的 信息 ,并发送”hello , client“ ,再退出
注意:需要在写出的内容后加入结束标记 socket.shutdownOutput();
server.java
public class server2 {
public static void main(String[] args) throws IOException {
//1. 在本机的 9999端口监听,等待连接
// 前提:要求在本机没有其他服务在监听9999
// serversocket 可以通过 accept() 方法 返回多个Socket[多个客户端连接服务端]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接");
//2.当没有客户端连接9999端口时,程序会 阻塞, 等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("socket="+ socket.getClass());
// 3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据,显示
InputStream inputStream = socket.getInputStream();
//4.IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while((readLen=inputStream.read(buf))!=-1){
System.out.println(new String(buf,0,readLen));
}
//5. 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello , client".getBytes());
//设置结束标记
socket.shutdownOutput();
//6.关闭流和socket
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
client.java
public class client2 {
public static void main(String[] args) throws IOException {
//1 . 连接服务器 (ip,端口)
//连接本机的9999端口
Socket socket = new Socket(Inet6Address.getLocalHost(), 9999);
System.out.println("客户端 socket返回 ="+ socket.getClass());
//2.连接上后,生成socket,通过socket.getOutputStream()
//得到 和 socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3. 通过输出流 , 写入数据到 数据通道
outputStream.write("hello,server".getBytes());
//设置结束标记
socket.shutdownOutput();
//4. 获取和socket相关联的输入流,读取数据(字节),并显示
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLen = 0 ;
while((readLen=inputStream.read(buf))!= -1){
System.out.println(new String(buf,0,readLen));
}
//5.关闭流对象和socket , 必须关闭
inputStream.close();
outputStream.close();
socket.close();
System.out.println("客户端退出");
}
}
案例3 —— 使用字符流
- 编写一个服务器,和一个客户端
- 服务器端在 9999 端口监听
- 客户端连接到服务端,发送 “hello,server" , 并接受服务器端回发的 ”hello,client“,再退出
- 服务器端接收到 客户端发送的 信息 ,并发送”hello , client“ ,再退出
为什么用字符流? 方便处理文本
注意:如果用 writer.newLine()
设置写入结束标记,那么必须要求对方使用readLine()的方式读取
server.java
public class server3 {
public static void main(String[] args) throws IOException {
//1. 在本机的 9999端口监听,等待连接
// 前提:要求在本机没有其他服务在监听9999
// serversocket 可以通过 accept() 方法 返回多个Socket[多个客户端连接服务端]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接");
//2.当没有客户端连接9999端口时,程序会 阻塞, 等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("socket="+ socket.getClass());
// 3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据,显示
InputStream inputStream = socket.getInputStream();
//4.IO读取,使用字符流 , 使用inputStreamReader 将 inputStream 转换成字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
//5. 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
//使用字符输出流的方式回复信息
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello client 字符流");
bufferedWriter.newLine();//插入一个换行符,表示回复内容的结束
bufferedWriter.flush();//注意需要手动的flush
//6.关闭流和socket 后打开的先关闭
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();
}
}
client.java
public class client3 {
public static void main(String[] args) throws IOException {
//1 . 连接服务器 (ip,端口)
//连接本机的9999端口
Socket socket = new Socket(Inet6Address.getLocalHost(), 9999);
System.out.println("客户端 socket返回 ="+ socket.getClass());
//2.连接上后,生成socket,通过socket.getOutputStream()
//得到 和 socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3. 通过输出流 , 写入数据到 数据通道, 使用字符流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello,server 字符流");
bufferedWriter.newLine(); //插入一个换行符,表示写入的内容结束,注意,要求对方使用readLine()!!!
bufferedWriter.flush(); //如果使用的字符流,需要手动刷新,否则数据不会写入数据通道
//4. 获取和socket相关联的输入流,读取数据(字符),并显示
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
//5.关闭流对象和socket , 必须关闭
bufferedReader.close();
bufferedWriter.close();
outputStream.close();
socket.close();
System.out.println("客户端退出");
}
}
UDP网络编程
基本介绍
- 类 DatagramSocket 和 DatagramPacket【数据报】实现了基于UDP协议网络程序。
- UDP数据报通过数据报套接字 DatagramSocket 发送和接收, 系统不保证UDP数据报一定能够安全送到目的地, 也不确定什么时候可以抵达。
- DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号
- UDP协议中每个数据报都给出了完整的地址信息,因此无序建立发送方和接收方的连接
基本流程
- 核心的两个类/对象 DatagramSocket 和 DatagramPacket
- 建立发送端,接收端(没有服务端和客户端概念)
- 发送给数据前,建立数据报 DatagramPacket对象
- 调用DatagramSocket的发送、接收方法
- 关闭DatagramSocket
案例
- 编写一个接收端A,和一个发送端B
- 接收端A在9999端口等待接收数据(receive)
- 发送端B向接收端A 发送 数据 “hello,明天吃火锅~”
- 接收端A 接收到 发送端B发送的数据,回复“好的,明天见“,再退出
- 发送端接收 回复的数据,再退出
receiveA.java
public class receiverA {
public static void main(String[] args) throws IOException {
//1. 创建一个 DatagramSocket 对象,准备在 9999 接收数据
DatagramSocket socket = new DatagramSocket(9999);
//2. 构建一个 DatagramPacket 对象,准备接收数据
// 在前面讲解 UDP 协议时,老师说过一个数据包最大 64k
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
//3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
// 填充到 packet 对象
//老师提示: 当有数据包发送到 本机的 9999 端口时,就会接收到数据
// 如果没有数据包发送到 本机的 9999 端口, 就会阻塞等待.
System.out.println("接收端 A 等待接收数据..");
socket.receive(packet);
//4. 可以把 packet 进行拆包,取出数据,并显示.
int length = packet.getLength();//实际接收到的数据字节长度
byte[] data = packet.getData();//接收到数据
String s = new String(data, 0, length);
System.out.println(s);
//===回复信息给 B 端
//将需要发送的数据,封装到 DatagramPacket 对象
data = "好的, 明天见".getBytes();
//说明: 封装的 DatagramPacket 对象 data 内容字节数组 , data.length , 主机(IP) , 端口
packet =
new DatagramPacket(data, data.length, InetAddress.getByName("10.20.53.111"), 9998);
socket.send(packet);//发送
//5. 关闭资源
socket.close();
System.out.println("A 端退出...");
}
}
senderB.java
public class senderB {
public static void main(String[] args) throws IOException {
//1.创建 DatagramSocket 对象,准备在 9998 端口 接收数据
DatagramSocket socket = new DatagramSocket(9998);
//2. 将需要发送的数据,封装到 DatagramPacket 对象
byte[] data = "hello 明天吃火锅~".getBytes(); //
//说明: 封装的 DatagramPacket 对象 data 内容字节数组 , data.length , 主机(IP) , 端口
DatagramPacket packet =
new DatagramPacket(data, data.length, InetAddress.getByName("10.20.53.111"), 9999);
socket.send(packet);
//3.=== 接收从 A 端回复的信息
//(1) 构建一个 DatagramPacket 对象,准备接收数据
// 在前面讲解 UDP 协议时,老师说过一个数据包最大 64k
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
//(2) 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
// 填充到 packet 对象
//老师提示: 当有数据包发送到 本机的 9998 端口时,就会接收到数据
// 如果没有数据包发送到 本机的 9998 端口, 就会阻塞等待.
socket.receive(packet);
//(3) 可以把 packet 进行拆包,取出数据,并显示.
int length = packet.getLength();//实际接收到的数据字节长度
data = packet.getData();//接收到数据
String s = new String(data, 0, length);
System.out.println(s);
//关闭资源
socket.close();
System.out.println("B 端退出");
}
}