24、网络编程

一、网络基础

1 软件结构

C/S结构:如qq,微信,360

C =》 Client:表示客户端
S =》 Server:表示服务器端

B/S结构:如火狐浏览器,谷歌浏览器,IE

B =》 Browser:表示浏览器
S =》 Server:表示服务器端

**无论是C/S结构还是B/S结构都离不开网络通信****

2 网络通信协议

image-20220305210941067

2.1 TCP&UDP

互联网上运行的计算机使用传输控制协议(TCP)或用户数据报协议(UDP)相互通信

TCP(传输控制协议)

TCP是基于连接的协议,在两台计算机之间提供可靠的数据流

TCP为需要可靠通信的应用程序提供了点对点通道

UDP(用户数据报协议)

UDP(用户数据报协议),它从一台计算机到另外一台计算机发送独立的数据包(称为数据报),但不能保证其到达。UDP不想TCP那样基于链接。

UDP协议提供了网络上两个应用程序无法保证的通信。UDP不像TCP那样基于连接,而是将独立的数据报从一个应用程序发送到另一个应用程序,发送数据报就像通过邮局发送一封信:传递顺序不重要,也不能保证,每条消息彼此独立。

许多防火墙和路由器已配置不允许UDP数据包。

2.2 IP和端口

IP和端口

  • IP:定位计算机
  • 端口:定位计算机上的具体程序
一般来说,计算机与网络具有单个物理连接。发送到特定计算机的所有数据通过该连接到达,但是数据可能打算供计算机上运行的不同应用程序使用,那么计算机如何知道将数据转发到哪个应用程序?——通过使用端口。

通过Internet传输的数据带有寻址信息,该信息标识了计算机及其发往的窗口。该计算机由其32位IP地址标识,该IP地址用于将数据传递到网络上正确的计算机。端口由一个16位数字标识,TCP和UDP使用该16位数字将数据传递到正确的应用程序。

端口号的范围是【0-65,535】,因为端口由16位数字表示。不过端口号范围从0-1023被限制,保留供HTTP和FTP等知名服务以及其他系统使用。这些端口你的应用程序不应该尝试绑定。

2.3 URL

URL:定位计算机上的资源

URL是“统一资源定位符”的缩写:表示互联网上的资源

URL具有两个主要组成部分:访问资源所需要的协议和资源的位置

二、套接字Socket

image-20220305211008032

1 什么是Socket

套接字(Socket)是网络上运行的两个程序之间双向通讯连接的一个端点。套接字类用于表示客户端程序和服务器程序之间的连接。java.net包提供了两个类——Socket和ServerSocket分别实现连接的客户端和连接的服务器

image-20220306115842055

2 如何使用Socket

image-20220305211557607

image-20220305211739944

通常,服务器在特定计算机上运行,并具有绑定到特定端口号的套接字。服务器只是等待,侦听套接字请求客户端发出的连接请求。

在客户端上:客户端知道服务器在其上运行的计算机的主机名以及服务器侦听的端口号,为了发出连接请求,客户端尝试在服务器的机器和端口上与服务器会合。客户端还需要向服务器标识自己,以便客户端绑定到在此连接期间将使用本地的端口号。这个端口通常由系统分配。

Socket常用构造方法

//创建一个套接字,连向给定IP的主机,并与该主机给定端口的应用通信
//port:
public Socket(String host, int port) throws UnknowHostException, IOException;

//创建一个套接字,连向给定IP信息的主机,并该主机给定端口的应用通信
public Socket(InetAddress address, int port) throws IOException;

Socket常用方法

//获取读取数据的通道
public InputStream getInputStream() throws IOException;

//获取输出数据的通道
public OutputStream getOutputStream() throws IOException;

//设置连接的超时时间,0表示不会超时
public synchronized void setSoTimeout(int timeout) throws SocketException;

//标识输入通道不再接收数据,如果再次向通道中读取数据,则返回-1表示读取到末尾
public void shutdownInput() throws IOException;

//禁用输出通道,如果再次向通道中输入数据,则会报错
public void shutdownOutput() throws IOException;

//关闭套接字,相关数据通道会关闭
public synchronized void close() throws IOException;

ServerSocket常用构造方法

//创建一个服务器套接字并占用给定的端口
public ServerSocket(int port) throws IOException;

ServerSocket常用方法

//侦听与此套接字建立的连接并接受它,该方法将阻塞,直到建立连接为止
public Socket accept() throws IOException;

//设置连接的超时时间,0表示不会超时
public synchronized void setSoTimeout(int timeout) throws SocketException;
示例:Socket实现TCP

image-20220306145036812

/**
 * Socket套接字相关功能封装:信息接收,信息发送
 */
public class TcpSocketUtil {

    /**
     * 接收套接字中的信息
     * @param socket 套接字
     * @return
     * @throws IOException
     */
    public static String receiveMsg(Socket socket) throws IOException {
        //读取客户端传输的信息——字节流转为字符流
        InputStream is = socket.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader reader = new BufferedReader(isr);
        StringBuilder builder = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            builder.append(line);
        }
        socket.shutdownInput();
        return builder.toString();
    }

    /**
     * 向套接字中发送信息
     * @param socket 套接字
     * @param msg 发送的信息
     * @throws IOException
     */
    public static void sendMsg(Socket socket, String msg) throws IOException {
        //获取客户端输出的通道
        OutputStream os = socket.getOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os);
        BufferedWriter writer = new BufferedWriter(osw);
        writer.write(msg);
        writer.flush();
        //客户端输出完成,如果再次向通道中输入数据,报错
        socket.shutdownOutput();
    }
}
/**
 * 服务器端
 */
public class TcpServer {

    private ServerSocket server;//服务器套接字

    public Server(int port) throws IOException {
        this.server = new ServerSocket(port);
    }

    /**
     * 服务器启动
     */
    public void start() {
        //服务器不能挂,因此使用死循环
        while (true) {
            try {
                //等待客户端连接,程序会被阻塞,与Scanner的next()一样
                Socket connectionClient = server.accept();
                String msg = SocketUtil.receiveMsg(connectionClient);
                System.out.println(msg);
                SocketUtil.sendMsg(connectionClient, "服务器已接收到信息!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {

        try {
            Server server = new Server(6666);
            server.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 客户端
 */
public class TcpClient {

    private Socket client;//客户端套接字

    public Client(String ip, int port) throws IOException {
        client = new Socket(ip, port);
    }

    /**
     * 客户端发送信息
     * @param msg
     */
    public void sendMsg(String msg) throws IOException {
        SocketUtil.sendMsg(client, msg);
    }

    public String receiveMsg() throws IOException {
        return SocketUtil.receiveMsg(client);
    }

    public static void main(String[] args) {

        try {
            //本机的表达方式:localhost     127.0.0.1
            Client client = new Client("localhost", 6666);
            client.sendMsg("hello, DarkSky");
            System.out.println(client.receiveMsg());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、数据报Datagram

1 什么是数据报

数据报(Datagram)使网络层数据单元在介质上传输信息的一种逻辑分组格式,它是一种在网络中传播的、独立的、自身包含地址信息的消息,它能否到达目的地,到达的时间,到达时内容是否会变化不能准确知道的。它的通讯双方是不需要建立连接的,对于一些不需要很高质量的应用程序来说,数据报通讯是一个非常好的选择。

2 如何使用数据报

DatagramSocket常用构造方法

//构建一个绑定在任意端口的收发数据报的套接字
public DatagramSocket() throws SocketException;

//构建一个绑定在给定端口的收发数据报的套接字
public DatagramSocket(int port) throws SocketException;

DatagramSocket常用方法

//发送给定的数据包
public void send(DatagramPacket p) throws IOException;

//接收数据至给定的数据包
public synchronized void receive(DatagramPacket p) throws IOException;

//设置连接的超时时间,0表示不会超时
public synchronized void setTimeout(int timeout) throws SocketException;

DatagramPacket常用构造方法

//构建一个接收数据的数据包
public DatagramPacket(byte[] buf, int length);

//构建一个发送数据的数据包
public DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port);

DatagramPacket常用方法

//获取发送数据的主机IP地址
public synchronized InetAddress getAddress();

//获取发送数据的主机使用的端口
public synchronized int getPort();

//获取数据包中数据的长度
public synchronized int getLength();
示例:Socket实现UDP

image-20220306141954891

UDP网络通信基本流程

(1)核心的两个类/对象DatagramSocketDatagramPacket

(2)建立发送端和接收端(没有服务器端和客户端的概念)

(3)发送数据前,建立数据包/报 DatagramPacket对象

(4)调用DatagramPacket的发送和接收方法

(5)关闭DatagramPacket


四、InetAddress类

InetAddress概述

IP地址是IP使用的32位(IPv4)或者128位(IPv6)无符号数字,IP地址是传输层协议TCP,UDP的基础。

InetAddress是Java对IP地址的封装,几乎所有的Java网络相关的类都和它有关系。

InetAddress的实例对象包含已数字形式保存的IP地址,同时还可能包含主机名(InetAddress类提供了将主机名解析为IP地址(或反之)的方法)。

InetAddress的实例化

InetAddress类没有提供构造器,而是提供了两个静态方法来获取InetAddress实例

//根据指定主机名获取对应的IP地址(InetAddress对象)
public static InetAddress getByName(String host) throws UnknownHostException;

//根据提供的主机名和IP地址获取对应的InetAddress对象
public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException;

常用方法

//获取本地IP地址的主机名
static InetAddress 	getLocalHost();

// 返回 IP 地址字符串(以文本表现形式)
String 	getHostAddress();

//获取此 IP 地址的主机名
String 	getHostName();

//获取此 IP 地址的完全限定域名。
String 	getCanonicalHostName()
posted @ 2022-03-08 23:56  DarkSki  阅读(33)  评论(0编辑  收藏  举报