探索 Java 中的网络编程技术
网络编程就是 io 技术和网络技术的结合, 网络模型的定义, 只要共用网络模型就可以两者连接. 网络模型参考.
osi 模型
TCP/IP 参考模型
一座塔有七层, 我们需要闯关.
第一层物理层 ->第二层数据链路层 ->第三层网络层 ->第四层传输层 ->第五层会话层 ->第六层表示层 ->第七层应用层.
物理层是主要定义物理设备标准, 数据链路层是主要讲从物理层接收的数据进行 Mac 地址 (网卡的地址) 的封装与解封装. 这层的数据较帧.
网络层是将从下层接收到的数据进行 IP 地址的封装和解封装. 传输层是定义一些传输数据的协议和端口号.
会话层是将通过传输层建立数据传输的通路. 表示层是进行对接收的数据进行解释, 加密与解密.
应用层主要是一些终端的应用.
应用层 --> 传输层 --> 网络层 --> 主机至网络层
效果
效果
电脑通讯要点:
一需要 IP 地址: InetAddress(互联网协议即是规则)
二需要端口号
三需要传输协议
IP 地址, 网络中设备的标识, 不容易记住, 可以用主机名, 本地回环地址: 127.0.0.1 主机名就是 localhost 了. 所谓局域网就是局部范围内的, 互联网就是全球的.
端口号是用来标识进程的逻辑地址, 不同进行的标识, 有效的端口为 0 到 65535, 其中 0 到 1024 系统使用或保留的端口.
传输协议即是通讯的规则, 常见的协议为 TCP, UDP.
java.NET
类 InetAddress
- java.lang.Object
- -> java.NET.InetAddress
所有已实现的接口有:
Serializable
直接已知子类:
- Inet4Address, Inet6Address
- public class InetAddress extends Object implements Serializable
这个类表示互联网协议已地址.
效果
地址类型
- Class Inet6Address
- java.lang.Object
- java.NET.InetAddress
- java.NET.Inet6Address
- public final class Inet6Address extends InetAddress
效果
获取 ip 地址:
- public class IPDemo {
- public static void main(String[] args) throws UnknownHostException {
- // 获取本地主机地址对象
- InetAddress ip = InetAddress.getLocalHost();
- System.out.println(ip.getHostAddress() + ":" + ip.getHostName());
- }
- }
域名解析
C:\Windows\system32\drivers\etc
InetAddress 方法
类型 | 方法 | 说明 |
---|---|---|
boolean | equals(Object obj) | 将此对象与指定对象进行比较 |
byte[] | getAddress() | 返回此 InetAddress 对象的原始 ip 地址. |
static InetAddress[] | getAllByName(String host) | 给定主机的名称, 根据系统上配置的名称服务返回其 ip 地址数组. |
static InetAddress | getByAddress(byte[] addr) | 给出原始 IP 地址的 InetAddress 对象 |
static InetAddress | getByAddress(String host, byte[] addr) | 根据提供的主机名和 ip 地址创建 InetAddress |
static InetAddress | getByName(String host) | 确定主机名称的 ip 地址 |
String | getCanonicalHostName() | 获取此 ip 地址的完全限定域名 |
String | getHostAddress() | 返回文本显示中的 ip 地址字符串 |
String | getHostName() | 获取此 ip 地址的主机名 |
网络编程:
1, 网络模型: 7 层 --->4 层
端口
用于标识进程的逻辑地址, 不同进程的标识
有效端口: 0 到 65535, 而 0 到 1024 系统使用或保留端口
传输协议
常见协议 TCP``UDP
TCP 和 UDP 的区别:
TCP: 面向连接, 通过三次握手完成, 速度慢, 可靠.
UDP: 面向无连接, 速度快, 不可靠.
UDP 是将数据及其源和目的封装成数据包中, 不需要建立连接, 每个数据报的大小在限制在 64k 内, 因无连接, 是不可靠的协议, 不需要连接, 但是速度快.
TCP 是需要进行连接的, 形成传输数据的通道, 在连接中进行大数据量传输, 通过三次握手完成连接, 是可靠的协议, 效率低即是速度慢一点.
网络编程 - Socket
网络通讯的要素:
ip
端口
传输协议
ip 是用于标识网络中主机的数字标识, 而端口是用于标识应用程序的数字, 还有传输协议是用于进行数据传输的规则.
实现 UDP 的通信, TCP 传输: 客户端, 服务端.
Socket 是网络服务提供的一种机制, 是通信两端必备的, 都要有 Socket, 网络通信其实就是 Socket 间的通信, 数据在两个 Socket 间通过 io 传输.
两端发送端和接收端 - UDP
UDP 发送端 Demo
- public class UDPSend{
- public static void main(String[] args){
- System.out.println("udp 发送端");
- }
- }
- DatagramSocket
- public class DatagramSocket extends Object
此类表示用来发送和接收数据报包的套接字.
数据报套接字是包投递服务的发送或接收点. 每个在数据报套接字上发送或接收的包都是单独编址和路由的. 从一台机器发送到另一台机器的多个包可能选择不同的路由, 也可能按不同的顺序到达.
在 DatagramSocket 上总是启动 UDP 广播发送. 为了接收广播包, 将 DatagramSocket 绑定到通配符地址.
效果
void receive(DatagramPacket p)
从此套接字接收数据报包
send(DatagramPacket p)
从此套接字发送数据报包
- public class UDPSend{
- public static void main(String[] args) throws IOException{
- System.out.println("udp 发送端");
- DatagramSocket ds = new DatagramSocket();
- String text = "hello";
- byte[] buf = text.getBytes();
- // 将数据转成字节数组
- DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("123.23232.323.2"),10000);
- ds.send(dp);
- ds.close();
- }
- }
- // 建立 upd 的 socket, 具备发送或接收功能
- // 将数据封装到数据包中, 数据包对象是 DatagramPacket.
- // 使用 socket 对象的 send 方法将数据包发出去.
- // 关闭资源
udp 接收端
- public class updDemo {
- public static void main(String[] args) throws IOException {
- System.out.println("udp 接收端");
- // 先有 udpsocket 服务
- // 接收数据
- DatagramSocket ds = new DatagramSocket();
- byte[] buf = new byte[1024];
- DatagramPacket dp = new DatagramPacket(buf, buf.length);
- ds.receive(dp);
- String ip = dp.getAddress().getHostAddress();
- int port = dp.getPort():
- String text = new String(dp.getData(),0,dp.getLength());
- // 关闭资源.
- ds.close();
- }
- }
- receive
- public void receive(DatagramPacket p) throws IOException
此套接字接收数据报包
实现 UDP 的通信, udp 传输涉及的两个对象, 即可以发送, 又可以接收. TCP 传输: 客户端, 服务端.
UDP 键盘输入
- public class UDPSend {
- public static void main(String[] args) throws IOException {
- System.out.println("udp 发送端 run");
- // 1, 建立 udp 的 socket 它具备者发送或者接收功能.
- DatagramSocket ds = new DatagramSocket(9999);
- // 2, 将数据封装到数据包中. 数据包对象是 DatagramPacket. 数据来自于键盘录入.
- BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
- String line = null;
- while((line=bufr.readLine())!=null){
- if("over".equals(line)){
- break;
- }
- byte[] buf = line.getBytes();// 将数据转成字节数组.
- // 将字节数组封装到数据包中.
- DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.223"), 10001);
- // 3, 使用 socket 对象的 send 方法将数据包发送出去.
- ds.send(dp);
- }
- // 4, 关闭资源.
- ds.close();
- }
- }
- public class UDPRece {
- public static void main(String[] args) throws IOException {
- System.out.println("udp2 接收端 run");
- DatagramSocket ds = new DatagramSocket(10001);
- while (true) {
- // 2, 接收数据.
- // 3, 先定义数据包.
- byte[] buf = new byte[1024];
- DatagramPacket dp = new DatagramPacket(buf, buf.length);
- ds.receive(dp);
- // 4, 通过数据包对象获取数据包的内容, 发送端的 ip. 发送端的端口, 发送过来的数据.
- String ip = dp.getAddress().getHostAddress();
- int port = dp.getPort();
- String text = new String(dp.getData(), 0, dp.getLength());
- System.out.println(ip + ":" + port + ":" + text);
- }
- // 5, 关闭资源.
- // ds.close();
- }
- }
案例:
- public class UDPChatTest {
- public static void main(String[] args) throws IOException {
- // 发送端的 socket 接收端的 socket
- DatagramSocket sendSocket = new DatagramSocket();
- DatagramSocket receSocket = new DatagramSocket(10002);
- // 创建任务对象.
- Send send = new Send(sendSocket);
- Rece rece = new Rece(receSocket);
- // 创建线程并开启.
- Thread t1 = new Thread(send);
- Thread t2 = new Thread(rece);
- t1.start();
- t2.start();
- }
- }
- // 发送任务
- class Send implements Runnable {
- private DatagramSocket ds;
- public Send(DatagramSocket ds) {
- super();
- this.ds = ds;
- }
- @Override
- public void run() {
- try {
- BufferedReader bufr = new BufferedReader(new InputStreamReader(
- System.in));
- String line = null;
- while ((line = bufr.readLine()) != null) {
- byte[] buf = line.getBytes();// 将数据转成字节数组.
- DatagramPacket dp = new DatagramPacket(buf, buf.length,
- InetAddress.getByName("192.168.1.223"), 10002);
- ds.send(dp);
- if ("886".equals(line)) {
- break;
- }
- }
- // 4, 关闭资源.
- ds.close();
- } catch (IOException e) {
- }
- }
- }
- // 接收任务.
- class Rece implements Runnable {
- private DatagramSocket ds;
- public Rece(DatagramSocket ds) {
- super();
- this.ds = ds;
- }
- @Override
- public void run() {
- while (true) {
- try {
- byte[] buf = new byte[1024];
- DatagramPacket dp = new DatagramPacket(buf, buf.length);
- ds.receive(dp);// 阻塞
- String ip = dp.getAddress().getHostAddress();
- int port = dp.getPort();
- String text = new String(dp.getData(), 0, dp.getLength());
- System.out.println(ip + ":" + port + ":" + text);
- if(text.equals("886")){
- System.out.println(ip+".... 离开聊天室");
- }
- } catch (IOException e) {
- }
- }
- }
- }
tcp 案例:
- public class TCPClient {
- public static void main(String[] args) throws IOException {
- System.out.println("客户端运行.......");
- // 1, 建立 tcp 的客户端 socket. 明确服务端的地址和端口.
- Socket s = new Socket("192.168.1.223",10003);
- // 2, 如果通道建立成功就会出现 socket io 流.
- // 客户端需要做的就获取 socket 流的中输出流将数据发送目的地服务端.
- OutputStream out = s.getOutputStream();
- // 3, 通过 socket 输出流将数据发送.
- out.write("hello tcp 来了!".getBytes());
- // 4, 关闭资源.
- s.close();
- }
- }
- public class TCPServer {
- public static void main(String[] args) throws IOException {
- System.out.println("服务端开启.....");
- ServerSocket ss = new ServerSocket(10003);
- while (true) {
- Socket s = ss.accept();
- String ip = s.getInetAddress().getHostAddress();
- InputStream in = s.getInputStream();
- byte[] buf = new byte[1024];
- int len = in.read(buf);
- String text = new String(buf, 0, len);
- System.out.println(text);
- s.close();
- }
- }
- }
来源: http://www.jianshu.com/p/aee2765b0732