- 网络编程三要素
- IP
- 端口
- 协议:连接和通信的规则
1 InetAddress
InetAddress
是 Java 中的一个类,它用于封装 IP 地址。这个类是 java.net
包的一部分,提供了对 IP 地址的操作,包括 IPv4 和 IPv6 地址。没有对外提供构造方法,需要使用静态方法获取对象。
以下是 InetAddress
类的一些常见用途:
- 获取本地主机的 IP 地址:可以使用
InetAddress.getLocalHost()
方法获取本地主机的 IP 地址。 - 通过主机名获取 IP 地址:可以使用
InetAddress.getByName(String host)
方法通过主机名获取其 IP 地址。 - 通过 IP 地址获取主机名:可以使用
InetAddress.getByName(String ip)
方法通过 IP 地址获取主机名。 - 获取 IP 地址的字节表示:可以使用
InetAddress.getAddress()
方法获取 IP 地址的字节表示。
2 协议
UDP:
- 用户数据报协议
- 面向无连接通信协议
- 速度快,有大小限制(一次最大64K),数据不安全,容易丢包
TCP:
- 传输控制协议
- 面向连接通信协议
- 速度慢,没有大小限制,数据安全。
2.1 UDP:
2.1.1 UDP发送数据:
步骤:
- 创建DatagramSocket对象
- 打包发送内容、确定目标IP与端口
- 发送
- 关闭DatagramSocket
示例:
public static void main(String[] args) throws IOException {
Scanner sc=new Scanner(System.in);
byte[] buf=new byte[1024];
//创建DatagramSocket对象、指定发送端口
DatagramSocket ds=new DatagramSocket();//发送端的端口不重要
//指定发送到的IP和端口
InetAddress address=InetAddress.getByName("127.0.0.1");
int port = 10086;
while (true){
String str=sc.nextLine();
if (str.equals("quit"))
break;
//打包
buf=str.getBytes("UTF-8");
DatagramPacket dp=new DatagramPacket(buf,buf.length,address,port);
//发送
ds.send(dp);
}
ds.close();
}
2.1.2 UDP接收数据:
步骤:
- 创建
DatagramSocket
实例:- 创建一个
DatagramSocket
对象,这个对象将用于监听指定端口上的数据报。
- 创建一个
- 创建字节数组:
- 准备一个字节数组,用于存储接收到的数据。数组的大小应该足够大,以确保能够接收预期的数据量。
- 创建
DatagramPacket
实例:- 创建一个
DatagramPacket
对象,这个对象将用于存储接收到的数据。你需要提供之前创建的字节数组和数组的大小作为参数。
- 创建一个
- 接收数据:
- 使用
DatagramSocket
的receive
方法来接收数据。这个方法是阻塞的,意味着它会等待直到接收到一个数据报或者发生异常。
- 使用
- 处理接收到的数据:
- 一旦
receive
方法返回,DatagramPacket
对象将包含接收到的数据。你可以使用DatagramPacket
提供的方法来访问这些数据,例如getData()
和getLength()
来获取数据和数据的长度。
- 一旦
示例:
public static void main(String[] args) throws IOException {
//创建一个DatagramSocket,并指定它绑定到端口10086。这意味着该程序将监听端口10086上的数据报。
DatagramSocket ds=new DatagramSocket(10086);
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
while (true) {
//接收
ds.receive(dp);//receive是阻塞的
//解包
byte[] data=dp.getData();//注意此处是新byte数组
int len= dp.getLength();//实际信息数据
String message = new String(data,0,len,"UTF-8");
System.out.println("来自"+dp.getAddress().getHostName()+"的"+dp.getAddress().getHostAddress()+"发送了: "+message);
}
}
2.1.3 UDP的三种通信方式:
- 单播:同上例
- 组播:一组接收端加入到一个IP地址
- 224.0.0.0~239.255.255.255
- 广播:发送给同一个局域网的主机
- 地址:255.255.255.255
2.2 TCP:
- 一种可靠的网络协议,在通信的两端各建立一个Socket对象。
- 通信之前要保证连接建立
- 通过Socket产生IO流来进行网络通信
2.2.1 客户端:
步骤:
- 创建客户端的Socket对象与指定服务端连接:
- Socket(String IP,int port)
- 获取输出流,写数据
- OutputStream getOutputStream()
- 释放资源
- void close()
2.2.1 服务端:
步骤:
- 创建服务器端的Socket对象(SeverSocket)
- ServerSocket(int port)
- 监听客户端连接,返回一个Socket对象
- Socket accept()
- 获取输入流,读数据,操作数据
- InputStream getInputStream()
- 释放资源
- void close()
示例:
ClientTest.java
public class ClientTest {
public static void main(String[] args) throws IOException {
//创建 Socket 对象,在创建对象的同时连接服务费。连接失败会报错
Socket socket =new Socket("127.0.0.1",10086);
OutputStream os=socket.getOutputStream();
os.write("你好你好,".getBytes(StandardCharsets.UTF_8));
os.close();
socket.close();
}
}
Server.java
public static void main(String[] args) throws IOException {
//创建服务端ServerSocket对象,指定监听端口
ServerSocket serverSocket=new ServerSocket(10086);
//创建socket对象接收ss返回的socket
Socket socket=serverSocket.accept();
//获取输入流,读数据,操作数据
InputStream is=socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);//字节流只会一个字节一个字节读取,会使中文乱码,需要转换流转为字符流
int b;
while ((b=isr.read())!=-1){
System.out.print((char) b);
}
is.close();
socket.close();
serverSocket.close();
}
3 TCP聊天室练习
Server.java:
package exercise1;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
System.out.println("服务器上线!");
ServerSocket serverSocket=new ServerSocket(10086);
Socket socket=serverSocket.accept();
InputStream inputStream=socket.getInputStream();
InputStreamReader isr=new InputStreamReader(inputStream);
int b;
while ((b= isr.read())!=-1){
System.out.print("来自"+socket.getInetAddress().getHostName()+": ");
System.out.print((char)b);
}
isr.close();
socket.close();
isr.close();
}
}
Client.java:
package exercise1;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.spi.InetAddressResolver;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket=new Socket("172.25.201.95",10086);
OutputStream os=socket.getOutputStream();
Scanner scanner=new Scanner(System.in);
System.out.println("上线!输入 quit 退出!");
while (true){
System.out.println("请输入你要发送的信息:");
String message = scanner.nextLine()+"\n";
if(message.equals("quit\n")){
System.out.println("下线!");
message=InetAddress.getLocalHost().getHostName()+"下线!\n";
os.write(message.getBytes(StandardCharsets.UTF_8));
break;
}
message="来自"+InetAddress.getLocalHost().getHostName()+"的信息:"+message;
os.write(message.getBytes(StandardCharsets.UTF_8));
}
os.close();
socket.close();
}
}