目录
基本的通信架构有两种形式:cs架构(Client客户端/Server服务端),BS架构(Browser浏览器/server服务端)。
[通信协议:UDP TCP](#通信协议:UDP TCP)
基本的通信架构有两种形式:cs架构(Client客户端/Server服务端),BS架构(Browser浏览器/server服务端)。
无论是cs架构,还是bs架构的软件都必须依赖网络编程!
java.net*包下提供了网络编程的解决方案!
网络编程的三要素:Ip,端口,协议
ip地址:设备在网络中的地址,是设备在网络中的唯一标识。
端口:应用程序在设备中的唯一标识。
协议:连接和数据在网络中传输的规则。
ip地址
ipv4,它使用32位地址,四字节,通常以点分十进制显示。
ipv6,他使用128位地址。 冒分十六进制表示法。
IP域名:用于在互联网上识别和定位网站的人类可读的名称。
DNS域名解析(Domain Name System)
是互联网中用于将域名转换成为对应ip地址的分布式命名系统。它充当了互联网的"电话薄",将易记的域名映射到数字化的ip地址,使得用户通过域名来访问网站和其他网站资源。
公网ip,内网ip
公网ip:是可以连接到互联网的ip地址。
内网ip:也叫局域网ip,是只能组织机构内部使用的ip地址;例如:192.168. 开头的就是常见的局域网地址,范围为192.168.0.0--192.168.255.255,专门为组织机构内部使用。
本机ip
127.0.0.1、localhost:代表本机ip,只会寻找当前程序所在的主机。
ip常见命令
ipconfig:查看本机ip地址。
ping ip地址:检查网络是否联通。
IP:inetAddress的常见方法
|------------------------------------------------------------------------------|------------------------------|
| InetAddress类的常用方法 | 说明 |
| public static InetAddress getLocalHost() throws UnknownHostException | 获得本机ip,返回一个InetAddress对象 |
| public String getHostName() | 获取该ip地址对象对应的主机名 |
| public String getHostAddress() | 获取该ip地址对象中的ip地址信息。 |
| public static InetAddress getByName(String host) throws UnknownHostException | 根据ip地址或者域名,返回一个inetAddress对象 |
| public boolean isReachable(int timeout)throws IOException | 判断主机在指定毫秒内与该IP对应的主机是否能连通 |
java
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressdemo1 {
public static void main(String[] args) {
try {
// 1. 获取本地主机名
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println("本地主机信息: " + ip1);
System.out.println("本地主机的IP地址: " + ip1.getHostAddress());
System.out.println("本地主机的主机名: " + ip1.getHostName());
// 2. 获取对方IP对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println("对方主机信息: " + ip2);
System.out.println("对方主机的IP地址: " + ip2.getHostAddress());
System.out.println("对方主机的主机名: " + ip2.getHostName());
// 3. 判断主机与对方主机是否互通
System.out.println("对方主机是否可达: " + ip2.isReachable(5000));
} catch (UnknownHostException e) {
System.out.println("无法找到主机: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
本地主机信息: lenovo/192.168.137.1
本地主机的IP地址: 192.168.137.1
本地主机的主机名: lenovo
对方主机信息: www.baidu.com/183.2.172.42
对方主机的IP地址: 183.2.172.42
对方主机的主机名: www.baidu.com
对方主机是否可达: true
Process finished with exit code 0
端口
用来标记正在计算机设备上运行的应用程序,被规定为一个16位的二进制,范围是0到65535。
端口分类
周知端口:0到1023,被预先定义的知名应用占用(如:HTTP占用80,FTP占用21)
注册端口:1024------49151,分配给用户进程或某些应用程序。
动态端口:49152到65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配。
注意:我们在开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则报错。
端口号的作用是什么?
唯一标识正在计算机设备上进行的进程(程序)
一个设备中,能否出现2个应用程序的端口号一样,为什么?
不可以,如果一样会出现端口冲突错误。
通信协议:UDP TCP
网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。
开放式网络互联标准:OSI网络参考模型。
TCP/IP网络模型:事实上的国际标志
传输层的2个通信协议
UDP:用户数据报协议
TCP:传输控制协议
UDP:特点:无连接,不可靠通信。
不事先建立连接,数据按照包发,一包数据包含:自己的ip、端口端口、目的地IP,端口和数据(限制在64kb内)。发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,固是不可靠的。通信效率高,视频直播。
TCP协议
特点:面向连接。可靠通信。
TCP的最终目的:要保证在不可靠的信道上实现可靠的数据传输。
TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接。
三次握手建立可靠连接
可靠连接:确保通信的双方首发消息都是没有问题的(全双工)
四次挥手断开连接
UDP通信的实现
UDP:特点:无连接,不可靠通信。
不事先建立连接,数据按照包发,一包数据包含:自己的ip、端口端口、目的地IP,端口和数据(限制在64kb内)。
java提供了一个java.net.DatagramSocket类来实现UDP通信。
DatagramSocket:用于创建客户端、服务端。
|---------------------------------|------------------------------|
| 构造器 | 说明 |
| public DatagramSocket() | 创建客户端的socket对象,系统会随时分配一个端口号。 |
| public DatagramSocket(int port) | 创建服务端的Socket对象,并指定端口号, |
|---------------------------------------|-----------|
| 方法 | 说明 |
| public void send(DatagramPacket dp) | 发送数据包 |
| public void receive(DatagramPacket p) | 使用数据包接收数据 |
DatagramPacket:创建数据包
|------------------------------------------------------------------------------|--------------|
| 构造器 | 说明 |
| public DatagramPacket(byte[ ]buf,int length,InetAddress address, int port) | 创建发出去的数据包对象。 |
| public DatagramPacket(byte[ ]buf, int length) | 创建用来接受数据的数据包 |
客户端
java
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UDPClientDemo1 {
public static void main(String[] args) throws Exception{
//目标:完成UDP通信的多发多收,客户端开发
DatagramSocket socket=new DatagramSocket();
Scanner sc=new Scanner(System.in);
//创建数据包对象封装要发送的数据
//参数一:要发送的数据
//参数二:数据长度
//参数三:目标主机的IP地址
//参数四:目标主机的端口号
System.out.println("客户端启动成功");
while(true) {
String msg = sc.nextLine();
if("886".equals(msg))
{
System.out.println("客户端退出");
socket.close();
break;
}
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length,
InetAddress.getLocalHost(), 8080);
socket.send(packet);
}
}
}
服务端
java
mport java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPServerDemo1 {
public static void main(String[] args) throws Exception{
//目标完成UDP服务器端程序
//1.定义一个服务器端,并且指定端口号
System.out.println("服务器端已经启动...");
DatagramSocket server =new DatagramSocket(8080);
//2.创建一个数据包,用于封装服务器端接收到的数据
byte[] data =new byte[1024*64];
DatagramPacket packet =new DatagramPacket(data,data.length);
while(true){
//3.接收客户端发送的数据
server.receive(packet);
//4.获取客户端发送的数据
String data2=new String(data,0,packet.getLength());
System.out.println("服务器端接收到的数据为:"+data2);
System.out.println("对方ip:"+packet.getAddress().getHostAddress()+"对方端口号:"+packet.getPort());
}
}
}
TCP通信
TCP的最终目的:要保证在不可靠的信道上实现可靠的数据传输。
TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接。
三次握手建立可靠连接。
java提供了一个java.net.Socket来实现Tcp通信。
|--------------------------------------|----------------------------------------------|
| 构造器 | 说明 |
| public Socket(string host. int port) | 根据指定的服务器ip,端口号请求与服务端建立连接,连接通过,就可以获得客户端socket |
|---------------------------------------|-----------|
| 方法 | 说明 |
| public OutputStream getOutputStream() | 获取字节输出流对象 |
| public InputStream getInputStream() | 获取自己输入流对象 |
服务端是通过java.net包下的ServerSocket类来实现的。
|-------------------------------|------------|
| 构造器 | 说明 |
| public ServerSocket(int port) | 为服务端程序注册端口 |
|------------------------|----------------------------------------------|
| 方法 | 说明 |
| public Socket accept() | 阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象。 |
客户端
java
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class TCPClientDemo1 {
public static void main(String[] args) {
try {
System.out.println("客户端启动");
Socket socket = new Socket("127.0.0.1", 9099);
System.out.println("已连接到服务器,IP地址: " + socket.getInetAddress().getHostAddress());
System.out.println("服务器端口: " + socket.getPort());
// 1. 获取输出流
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("请输入要发送的数据: ");
String data = sc.nextLine();
if("886".equals(data)){
System.out.println("客户端退出");
socket.close();
break;
}
dos.writeUTF(data);
dos.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务端
java
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServerDemo1 {
public static void main(String[] args) {
try {
// 1. 创建服务端Socket,并绑定监听端口
System.out.println("服务器端已经启动...");
ServerSocket ss = new ServerSocket(9099);
Socket s = ss.accept();
System.out.println("客户端已连接,IP地址: " + s.getInetAddress().getHostAddress());
System.out.println("客户端端口: " + s.getPort());
// 2. 获取输入流
InputStream is = s.getInputStream();
DataInputStream dos = new DataInputStream(is);
// 3. 读取数据
while (true) {
String name = dos.readUTF();
System.out.println( name);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
TCP通信-支持与多个客户端同时通信
线程
javascript
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;
public class ServerReader extends Thread {
private Socket s;
public ServerReader(Socket s)
{
this.s = s;
}
@Override
public void run()
{
try{
System.out.println("客户端已连接,IP地址: " + s.getInetAddress().getHostAddress());
System.out.println("客户端端口: " + s.getPort());
InputStream is = s.getInputStream();
DataInputStream dos = new DataInputStream(is);
String name = dos.readUTF();
System.out.println( name);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
客户端
java
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServerDemo1 {
public static void main(String[] args) {
try {
// 1. 创建服务端Socket,并绑定监听端口
System.out.println("服务器端已经启动...");
ServerSocket ss = new ServerSocket(9099);
// 3. 读取数据
while (true) {
Socket s = ss.accept();
//每接受一个客户端连接,就创建一个线程进行处理
new ServerReader(s).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}