网络通信

1、数据通过网络在设备之间进行传输

2、java.net 包提供相关类、接口完成网络通信

 

IP 地址

1、用于唯一标识网络中的每台主机

2、组成:网络地址 + 主机地址

3、IPv4:4 byte(32 bit)点分十进制

4、本机地址:127.0.0.1

5、IPv6:16 byte(128 bit)冒分十六进制

 

IPv4 分类

A类 0 + 7位网络号 + 24位主机号 0.0.0.0 ~ 127.255.255.255
B类 10 + 14位网络号 + 16位主机号 128.0.0.0 ~ 191.255.255.255
C类 110 + 21位网络号 + 8位主机号 192.0.0.0 ~ 223.255.255.255
D类 1110 + 28位多播组号 224.0.0.0 ~ 239.255.255.255
E类 11110 + 27位(待用) 240.0.0.0 ~ 247.255.255.255

 

域名

1、HTTP 协议将 IP 地址映射为域名

2、方便记忆

 

端口号

1、表示计算机上某个特定网络程序

2、表示形式:整数

3、端口范围:0 ~ 65535(216 - 1),两个字节表示端口

4、0 ~ 1024 端口已被占用

 

网络通信协议

1、TPC / IP:传输控制协议 / 因特网互联协议

TCP / IP 模型 模型各层对应协议
应用层 HTTP、ftp、telnet、DNS……
传输层 TCP、UDP……
网络层 IP、ICMP、ARP……
物理层 + 数据链路层 Link

2、TCP 协议

(1)使用前,必须先建立 TCP 连接,形成传输数据通道

(2)传输前,采用“三次握手”方式,是可靠的

(3)进行通信的两个应用进程:客户端、服务端

(4)连接中可以进行大量的数据传输

(5)传输完毕,需要释放已建立的连接,效率低

3、UDP 协议

(1)将数据、源、目的封装成数据包,不需要建立连接

(2)每个数据包大小限制在 64 KB 以内,不适合传输大量数据

(3)无需连接,是不可靠的

(4)因为不面向连接,发送数据结束时不需要释放资源,速度快

 

InetAddress 类

1、返回本地主机的地址,通过从系统检索主机的名称,然后将该名称解析为 InetAddress

public static InetAddress getLocalHost() throws UnknownHostException

2、返回回送地址

public static InetAddress getLoopbackAddress()

3、获取 InetAddress 对象的主机名

public String getHostName()

4、返回 InetAddress 对象的 IP 地址字符串

public String getHostAddress()

5、获取 InetAddress 对象的完全限定域名

public String getCanonicalHostName()

6、根据主机名 / 域名,获取IP地址

public static InetAddress getByName(String host) throws UnknownHostException

7、根据提供的主机名和IP地址创建 InetAddress

public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException

8、给出原始IP地址的 InetAddress 对象

public static InetAddress getByAddress(byte[] addr) throws UnknownHostException

9、给定主机的名称,根据系统上配置的名称服务返回其IP地址数组

public static InetAddress[] getAllByName(String host) throws UnknownHostException

10、返回此 InetAddress 对象的原始IP地址

public byte[] getAddress()

 

Socket 类

1、套接字:开发网络应用程序

2、通信两端都需要 Socket,是两台设备的通信端点

3、网络通信即 Socket 之间通信

4、Socket 允许程序把网络连接当作一个流,数据在两个 Socket 之间通过 IO 流传输

5、客户端:主动发起通信

6、服务端:等待通信请求

 

TCP 网络通信

1、基于客户端 - 服务端的网络通信

2、底层为 TCP / IP 协议

Server Client
ServerSocket(int port) -> Socket accept() <- -> Socket(InetAddress address, int port)
Socket.getInputStream() <- - Socket.getOutputStream()
Socket.getOutputStream() - -> Socket.getInputStream()
Socket.close() Socket.close()

3、(例)使用字节流

(1)服务端

public static void main(String[] args) throws IOException {
    //监听2000端口,等待连接
    ServerSocket serverSocket = new ServerSocket(2000);
    /*
    ServerSocket对象通过accept返回多个Socket对象,实现多个客户端连接并发
    没有客户端连接2000端口时,程序在accept阻塞
    客户端连接2000端口时,accept返回Socket对象
    */
    Socket socket = serverSocket.accept();
    BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
    BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
    byte[] bytes = new byte[1024];
    int length;
    while ((length = bis.read(bytes)) != -1) {
        System.out.println(new String(bytes, 0, length));
    }
    bos.write("data from Server".getBytes(StandardCharsets.UTF_8));
    bos.flush();
    socket.shutdownOutput();//设置结束标记
    bis.close();
    bos.close();
    socket.close();
    serverSocket.close();
}

(2)客户端

public static void main(String[] args) throws IOException {
    /*
    创建流套接字并将其连接到指定IP地址的指定端口号
    若连接服务端成功,返回Socket对象
    */
    Socket socket = new Socket(InetAddress.getLocalHost(), 2000);
    BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
    BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
    bos.write("data from Client".getBytes(StandardCharsets.UTF_8));
    bos.flush();
    socket.shutdownOutput();//设置结束标记
    byte[] bytes = new byte[1024];
    int length;
    while ((length = bis.read(bytes)) != -1) {
        System.out.println(new String(bytes, 0, length));
    }
    bos.close();
    bis.close();
    socket.close();
}

4、(例)使用字符流

(1)服务端

public static void main(String[] args) throws IOException {
    //监听2000端口,等待连接
    ServerSocket serverSocket = new ServerSocket(2000);
    /*
    ServerSocket对象通过accept返回多个Socket对象,实现多个客户端连接并发
    没有客户端连接2000端口时,程序在accept阻塞
    客户端连接2000端口时,accept返回Socket对象
    */
    Socket socket = serverSocket.accept();
    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    System.out.println(br.readLine());//readLine 要求客户端调用 newLine
    bw.write("String from Server");
    bw.newLine();//相当于结束标记,newLine 要求客户端调用 readLine
    bw.flush();
    br.close();
    bw.close();
    socket.close();
    serverSocket.close();
}

(2)客户端

public static void main(String[] args) throws IOException {
    /*
    创建流套接字并将其连接到指定IP地址的指定端口号
    若连接服务端成功,返回Socket对象
    */
    Socket socket = new Socket(InetAddress.getLocalHost(), 2000);
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    bw.write("String from Client");
    bw.newLine();//相当于结束标记,newLine 要求服务端调用 readLine
    bw.flush();
    System.out.println(br.readLine());//readLine 要求服务端调用 newLine
    bw.close();
    br.close();
    socket.close();
}

5、netstat 指令

(1)在命令提示符执行

(2)netstat -an:查看当前主机网络情况,包括端口监听、网络连接

(3)netstat -anb:除查看当前主机网络情况,还能查看使用不同端口的对应程序

(4)netstat -an | more 或 netstat -anb | more:可以分页显示,空格跳转到下一页

(5)LISTENING:表示某个端口在监听

(6)ESTABLISHED:表示对应的外部地址(客户端)连接到该端口

6、客户端连接服务端,实际也是通过端口与服务端通信,该端口由 TCP / IP 分配

 

UDP 网路通信

1、通过 DatagramSocket 发送、接收,可以指定端口接收数据,不保证数据包是否接收成功、何时接收

2、DatagramSocket 对象封装 UDP 数据包,或拆包、取出数据,包含发送端 IP 地址、端口号,接收方的 IP 地址、端口号

3、UDP 协议每个数据包都有完整地址信息,没有明确的服务端、客户端,变为数据的发送端、接收端

4、流程

(1)新建 DatagramSocket 对象,指定接收端口

(2)创建 DatagramPacket 对象,建立数据包,用于发送 / 接收数据

(3)调用 DatagramSocket 的发送、接收方法

(4)关闭 DatagramSocket

5、(例)

(1)A 端

public static void main(String[] args) throws IOException {
    DatagramSocket datagramSocket = new DatagramSocket(2000);
    byte[] bytes = new byte[1024 * 64];//数据包最大为64KB
    DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);//接收数据
    datagramSocket.receive(datagramPacket);//阻塞在receive,直到接收到数据
    byte[] data = datagramPacket.getData();//拆包、取出数据
    //datagramPacket.getLength()实际接收数据的字节长度
    System.out.println(new String(data,0,datagramPacket.getLength()));
    data = "data from A".getBytes(StandardCharsets.UTF_8);
    datagramPacket = new DatagramPacket(data,data.length, InetAddress.getLocalHost(),3000);//封装数据
    datagramSocket.send(datagramPacket);//发送数据
    datagramSocket.close();
}

(2)B 端

public static void main(String[] args) throws IOException {
    DatagramSocket datagramSocket = new DatagramSocket(3000);
    byte[] data = "data from B".getBytes(StandardCharsets.UTF_8);
    DatagramPacket datagramPacket =  new DatagramPacket(data,data.length, InetAddress.getLocalHost(),2000);//封装数据
    datagramSocket.send(datagramPacket);//发送数据
    byte[] bytes = new byte[1024 * 64];//数据包最大为64KB
    datagramPacket = new DatagramPacket(bytes,bytes.length);
    datagramSocket.receive(datagramPacket);//阻塞在receive,直到接收到数据
    data = datagramPacket.getData();
    //datagramPacket.getLength()实际接收数据的字节长度
    System.out.println(new String(data,0,datagramPacket.getLength()));
    datagramSocket.close();
}
posted @   半条咸鱼  阅读(271)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示