14. 网络编程


一、网络基础

??计算机网络把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大、功能强的网络系统,从而使众多的计算机可以方便的互相传递信息、共享硬件、软件、数据信息等资源。网络编程直接或间接地通过网络协议与其它计算机实现数据交换,进行通信。

OSI参考模型 TCP/IP参考模型 TCP/IP参考模型各层对应协议
应用层 应用层 HTTP、FTP、Telnet、DNS……
表示层
会话层
传输层 传输层 TCP、UDP……
网络层 网络层 IP、ICMP、ARP……
数据链路层 物理+数据链路层 Link
物理层

二、网络通信要素

2.1、IP和端口号

  • IP地址:InetAddress
    • 唯一的标识Internet上的计算机(通信实体)
    • 本地回环地址(hosAddress):127.0.0.1 主机名(hostName):localLost
    • IP地址分类方式1:IPV4 和 IPV6
      • IPV4:4个字节组成,4个0~255.大概42亿,其中30亿大概在北美,亚洲4亿。2011年已经用尽。以点分十进制表示
      • IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位标识,数之间用冒号分开
    • IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)
      • 192.168.开头的就是私有地址,范围即为192.168.0.0 ~ 192.168.255.255,专门位组织机构内部使用
  • 端口号:标识正在计算机上运行的进程(程序)
    • 不同的进程有不同的端口号
    • 被规定为 16 位的整数 0~65535
    • 端口分类:
      • 公认端口:0~1023。被预先定义的服务通信占用
      • 注册端口:1024~49151。分配给用户进程或应用程序
      • 动态/私有端口:49152~65535
  • 端口号与IP地址的组合得出一个网络套接字:Socket

2.2、网络协议

??计算机网络中实现通信必须有一些规定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等指定标准。在指定协议时,把复杂成份分解成一些简单的份,在将它们复合起来。最常用的复合方式是层次方式,即 同层间可以通信、上一层可以调用下一层,而与下一层不发生关系。各层互不影响,利于系统的开发和扩展。

2.2.1、TCP/IP协议簇

  • 传输层协议中有两个重要的协议:
    • 传输控制协议TCP(Transmission Control Protocol)
      • 使用TCP协议前,须建立TCP连接,形成传输数据通道
      • 传输前,采用“三次握手”的方式,点对点通信、是可靠的
      • TCP协议进行通信的两个应用进程:客户端、服务端
      • 在连接中可进行大数据量的传输
      • 传输完毕,需释放已建立的连接,效率低
    • 用户数据报协议UDP(User Datagram Protocol)
      • 将数据、源、目的封装成数据包,不需要建立连接
      • 每个数据包的大小限制在64K内
      • 发送不断对方是否准备好,接收方收到也不确认,故是不可靠的
      • 可以广播发送
      • 发送数据结束时无需释放资源,开销小,速度快
  • 网络互联协议IP(Internet Protocol)是网络层的组要协议,支持网间互联的数据通信
  • TCP/IP协议模型从更使用的角度出发,形成了高效的四层体系结构,即 物理链路层IP层传输层控制层

2.2.2、TCP网络编程例程

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

//服务端
public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream inputStream = null;
        ByteArrayOutputStream bArrayOutputStream = null;

        try {
            //1.创建服务器端的ServerSocket,指明自己的端口号
            serverSocket = new ServerSocket(55530);
            //2.调用accept()表示接收来自于客户端的socket
            socket = serverSocket.accept();
            //3.获取输入流
            inputStream = socket.getInputStream();

            //4.读取输入流中的数据
            bArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[5];
            int len;
            while((len = inputStream.read(buffer)) != -1){
                bArrayOutputStream.write(buffer, 0, len);
            }
            System.out.println("收到来自于" + socket.getInetAddress().getHostAddress() + "的数据");
            System.out.println(bArrayOutputStream.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5.关闭资源
            if(inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bArrayOutputStream != null){
                try {
                    bArrayOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

//客户端
public class Client {
    public static void main(String[] args) {
        InetAddress inetAddress = null;
        Socket socket = null;
        OutputStream outputStream  = null;

        try {
            //1.创建Scoket对象,指明服务器的ip和端口号
            inetAddress = InetAddress.getByName("127.0.0.1");
            socket = new Socket(inetAddress, 55530);

            //2.获取一个输出流,用于输出数据
            outputStream = socket.getOutputStream();
            //3.写出数据的操作
            outputStream.write("你好,我是客户端".getBytes());
            //关闭数据的输出
            socket.shutdownOutput();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.资源的关闭
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.2.3、UDP网络编程例程

  • 类DatagramSocket和DatagramPacket实现了基于UDP协议的网络程序
  • UDP数据报通过数据套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能安全送到目的地,也不能确定什么时候可与抵达
  • DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号
  • UDP协议中每个数据报都能给出了完整的地址信息,因此无需建立发送方和接收方的连接
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class Receiver {
    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;

        byte[] buffer = new byte[100];
        DatagramPacket datagramPacket = new DatagramPacket(buffer,0,buffer.length);

        try {
            datagramSocket = new DatagramSocket(9090);

            datagramSocket.receive(datagramPacket);
            System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (datagramSocket != null){
                datagramSocket.close();
            }
        }
    }
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class Sender {
    public static void main(String[] args) {
        String string = "我是UDP方式发送的数据";
        byte[] data = string.getBytes();

        DatagramSocket datagramSocket = null;
        DatagramPacket datagramPacket = null;
        InetAddress inetAddress = null;

        try {
            datagramSocket = new DatagramSocket();
            inetAddress = InetAddress.getLocalHost();
            datagramPacket = new DatagramPacket(data,0,data.length,inetAddress,9090);

            datagramSocket.send(datagramPacket);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2.4、URL网络编程

??URL(Uniform Resource Locator):统一资源定位符,它表示Internet上某一个资源的地址。它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。通过URL我们可以访问Internet上的各种网络资源。浏览器通过解析给定的URL可以在网络上查找相应的文件或其它资源。

URL的基本结构由5部分组成:

  • <传输协议>://<主机名>:<端口号>/<文件名>#判断名?参数列表
    • 判断名:即锚点

    • 参数列表格式:参数名=参数值&参数名=参数值……