JAVA网络编程
一、JAVA网络编程定义
1、什么是网络编程
- 网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。
- java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。通过直接使用这些类和接口,可以来专注于解决问题,而不用关注通信细节。
2、网络编程协议
java.net 包中提供了两种常见的网络协议的支持:
- TCP:TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
- UDP:UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层。一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。
二、IP和套接字
1、IP
- IP是Internet Protocol(网际互连协议)的缩写,是 TCP/IP 体系中的网际层协议。
- 设计IP的目的是提高网络的可扩展性:一是解决 互联网 问题,实现大规模、 异构网络 的互联互通;二是分割顶层网络应用和底层网络技术之间的耦合关系,以利于两者的独立发展。
- IP = (网络地址,主机地址)。
测试IP代码详解
import java.net.InetAddress;
import java.net.UnknownHostException;
public class MyIP {
public static void main(String[] args) throws UnknownHostException {
//查询本机地址
InetAddress myIP_01 = InetAddress.getByName("127.0.0.1");
System.out.println(myIP_01);
InetAddress myIP_02 = InetAddress.getByName("localhost");
System.out.println(myIP_02);
//查询本机
InetAddress myIP_03 = InetAddress.getLocalHost();
System.out.println(myIP_03);
//查询其他域名的IP地址
InetAddress otherIP = InetAddress.getByName("www.baidu.com");
System.out.println(otherIP);
//常用方法
System.out.println(otherIP.getAddress()); //返回字节流式IP地址
System.out.println(otherIP.getCanonicalHostName()); //返回规范IP地址
System.out.println(otherIP.getHostAddress()); //返回IP地址
System.out.println(otherIP.getHostName()); //返回域名
}
}
2、Socket(套接字)
- 套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。
- 一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。
- 从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口
- Socket = {IP地址, 端口号}
端口分类:
(1)、公用端口:0 ~ 1023
- HTTP协议:80
- HTTPS协议:443
- FTP协议:21
- Telent协议:20
… …
(2)、程序注册端口:1024 ~ 49151
- MySQL:3306
… …
(3)、动态私有端口:49152 ~ 65535
三、网络通信实现
1、Socket 编程
套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:
- 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
- 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
- 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
- Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
- 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。
2、ServerSocket 类
- 构造器
public ServerSocket(int port) throws IOException //创建绑定到特定端口的服务器套接字。
public ServerSocket(int port, int backlog) throws IOException //利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
public ServerSocket(int port, int backlog, InetAddress address) throws IOException //使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
public ServerSocket() throws IOException //创建非绑定服务器套接字。
3、Socket 类
- 构造器
public int getLocalPort() //返回此套接字在其上侦听的端口。
public Socket accept() throws IOException //侦听并接受到此套接字的连接。
public void setSoTimeout(int timeout) //通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。
public void bind(SocketAddress host, int backlog) //将ServerSocket 绑定到特定地址(IP 地址和端口号)。
4、代码详解
(1)、TCP
//客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
public class MySocket {
public static void main(String[] args) {
//创建客户端Socket引用对象mySocket
Socket mySocket = null;
//创建输出流OutputStream引用对象
OutputStream os = null;
try{
//获取服务器IP地址及服务器端口号
InetAddress myServerIP = InetAddress.getByName("127.0.0.1");
int post = 8888;
//构造套接字Socket
mySocket = new Socket(myServerIP,post);
//发送消息IO流,即业务实现
os =mySocket.getOutputStream();
os.write("你好呀".getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭输出流
if(os != null){
try {
os.close();
}catch (IOException e) {
e.printStackTrace();
}
}
//关闭客户端
if(mySocket != null){
try {
mySocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//服务器
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServerSocket {
public static void main(String[] args) throws IOException {
//创建服务器ServerScoket引用对象
ServerSocket myServerSocket = null;
//创建客户端Socket引用对象,用于服务器内部,等待客户端链接
Socket mySocket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
//实例化服务器对象并定义其端口号
myServerSocket = new ServerSocket(8888);
//等待客户端链接
mySocket = myServerSocket.accept();
//读取客户端消息
is = mySocket.getInputStream();
//通过管道流输出消息
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1){
baos.write(buffer, 0 , len);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
(2)、UDP
- UDP不区分客户端和服务器
//发送方
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class UdpSender {
public static void main(String[] args) throws IOException {
DatagramSocket senderSocket = new DatagramSocket(8888);
//无连接发送数据包裹
String str = "你好呀";
byte[] datas =str.getBytes();
DatagramPacket packet = new DatagramPacket(datas,0,datas.length, new InetSocketAddress("127.0.0.1", 6666)); //构建数据包裹
senderSocket.send(packet);//发送数据包裹
//关闭发送方
senderSocket.close();
}
//接收方
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpReceive {
public static void main(String[] args) throws IOException {
DatagramSocket receiveSocket = new DatagramSocket(6666);
//接收数据包裹
byte[] datas = new byte[1024];
DatagramPacket packet = new DatagramPacket(datas,0,datas.length);
receiveSocket.receive(packet); //阻塞式接受包裹
//打印数据
byte[] data = packet.getData();
String str = new String(data,0,data.length);
System.out.println(str);
//关闭接收方
receiveSocket.close();
}
}