Java网络编程

要想实现网络通信,需要解决的三个问题:

  • 问题1:如何准确确定定位网络上一台或多台主机

  • 问题2:如何定位主机上的特定的应用

  • 问题3:找到主机后,如何可靠、高效地进行数据传输

实现网络传输的三个要素:(对应解决三个问题)

> 使用IP地址(准确确定定位网络上一台或多台主机)

> 使用端口号(定位主机上的特定的应用)

> 规范网络通信协议(可靠、高效地进行数据传输)

通信要素1:IP地址

IP地址用来给网络中的一台计算机设备做唯一的编号

IP地址分类

> IP地址分类方式1

IPv4(占用4个字节)

IPv6(占用16个字节)

> IP地址分类方式2
公网地址(万维网使用)和 私有地址(局域网使用。以192.168开头)

本地回路地址

127.0.0.1(回环自检)

域名

便捷的记录ip地址,ip地址与域名一一对应

www.baidu.com www.atguigu.com www.bilibili.com

www.jd.com www.mi.com www.vip.com

端口号

> 可以唯一标识主机中的进程(应用程序)

> 不同的进程分配不同的端口号

> 范围:0~65535(两个字节)

通信协议

网络通信协议的目的

为了实现可靠而高效的数据传输。

网络参考模型

OSI参考模型:将网络分为7层,过于理想化,没有实施起来。

TCP/IP参考模型:将网络分为4层:应用层、传输层、网络层、物理+数据链路层。事实上使用的标准。

TCP: 可靠的连接(发送数据前,需要三次握手、四次挥手),进行大数据量的传输,效率低。

UDP: 不可靠的连接(发送前,不需要确认对方是否在)、使用数据报传输(限制在64kb以内)、效率高。

InetAddress的使用

作用

InetAddress类的一个实例就代表一个具体的ip地址。

实例化方式

InetAddress getByName(String host):获取指定ip对应的InetAddress的实例

InetAddress getLocalHost():获取本地ip对应的InetAddress的实例

常用方法

getHostName():获取域名,如果没有就获取ip地址

getHostAddress():获取ip地址

TCP

java 复制代码
import java.net.InetAddress;
import java.net.UnknownHostException;

public class Main {
    public static void main(String[] args) {
        try {
            //1. 实例化
            //getByName(String host): 获取指定ip对应的InetAddress的实例
            InetAddress inet1 = InetAddress.getByName("192.168.23.31");
            System.out.println(inet1);

            InetAddress inet2 = InetAddress.getByName("www.atguigu.com");
            System.out.println(inet2); //www.atguigu.com/122.228.95.175

            //getLocalHost(): 获取本地ip对应的InetAddress的实例
            InetAddress inet3 = InetAddress.getLocalHost();
            System.out.println(inet3); //DESKTOP-QCP2QPI/192.168.21.107

            InetAddress inet4 = InetAddress.getByName("127.0.0.1");
            System.out.println(inet4);

            //2. 两个常用的方法
            System.out.println(inet1.getHostName()); //192.168.23.31
            System.out.println(inet1.getHostAddress()); //192.168.23.31

            System.out.println(inet2.getHostName()); //www.atguigu.com
            System.out.println(inet2.getHostAddress()); //122.228.95.175
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}

UDP

java 复制代码
public void sender() throws Exception {
        //1. 创建DatagramSocket的实例
        DatagramSocket ds = new DatagramSocket();

        //2. 将数据、目的地的ip、目的地的端口号都封装在DatagramPacket数据报中
        InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
        int port = 9090;
        byte[] bytes = "我是发送端".getBytes("utf-8");
        DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, inetAddress, port);

        //3. 发送数据
        ds.send(packet);

        ds.close();
    }

    public void receiver() throws Exception {
        //1. 创建DatagramSocket的实例
        int port = 9090;
        DatagramSocket ds = new DatagramSocket(port);

        //2. 创建数据报的对象,用于接收发送端发送过来的数据
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);

        //3. 接收数据
        ds.receive(packet);

        //4. 获取数据,并打印到控制台上
        String str = new String(packet.getData(), 0, packet.getLength());
        System.out.println(str);

        ds.close();
    }

URL(Uniform Resource Locator)

统一资源定位符 (种子)

作用

一个具体的url就对应着互联网上某一资源的地址。

URL的格式:

http://192.168.21.107:8080/example/abcd.jpg?name=Tom ---> "万事万物皆对象"

应用层协议 ip地址 端口号 资源地址 参数列表

URL类的实例化及常用方法

  • public String getProtocol() 获取该URL的协议名

  • public String getHost() 获取该URL的主机名

  • public String getPort() 获取该URL的端口号

  • public String getPath() 获取该URL的文件路径

  • public String getFile() 获取该URL的文件名

  • public String getQuery() 获取该URL的查询名

java 复制代码
import java.net.URL;

public class Main {
    public static void main(String[] args) {
        String str = "http://192.168.21.107:8080/examples/abcd.jpg?name=Tom";

        try {
            URL url = new URL(str);

            /*
            * - public String getProtocol() 获取该URL的协议名
            - public String getHost() 获取该URL的主机名
            - public String getPort() 获取该URL的端口号
            - public String getPath() 获取该URL的文件路径
            - public String getFile() 获取该URL的文件名
            - public String getQuery() 获取该URL的查询名
            */

            System.out.println(url.getProtocol());
            System.out.println(url.getHost());
            System.out.println(url.getPort());
            System.out.println(url.getPath());
            System.out.println(url.getFile());
            System.out.println(url.getQuery());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

下载指定的URL的资源到本地

java 复制代码
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {
    public static void main(String[] args) throws IOException {
        // 1、获取URL实例
        URL url = new URL("http://127.0.0.1:8080/examples/abcd.jpg");
        // 2、建立与服务器的链接
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        // 3、获取输入流、创建输出流
        InputStream is = urlConnection.getInputStream();
        File file = new File("dest.jpg");
        FileOutputStream fos = new FileOutputStream(file);
        // 4、读写数据
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }
        System.out.println("文件下载成功");

        // 5、关闭资源
        fos.close();
        is.close();
        urlConnection.disconnect();
    }
}

练习

客户端发送内容给服务端,服务端将内容打印到控制台上。

java 复制代码
public void client() {
        Socket socket = null;
        OutputStream os = null;
        try {
            // 1、创建一个Socket
            InetAddress inetAddress = InetAddress.getByName("192.168.21.107"); //声明对方的ip地址
            int port = 8989; //声明对方的端口号
            socket = new Socket(inetAddress, port);

            // 2、发送数据
            os = socket.getOutputStream();
            os.write("你好,我是客户端,请多多关照".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 3、关闭socket、关闭流
            try {
                if (os != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (os != null)
                    os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void server() {
        ServerSocket serverSocket = null;
        Socket socket = null; //阻塞式的方法
        InputStream is = null;
        try {
            // 1、创建一个ServerSocket
            int port = 8989;
            serverSocket = new ServerSocket(port);

            // 2、调用accept(),接收客户端的Socket
            socket = serverSocket.accept();
            System.out.println("服务器端已开启");

            System.out.println("收到了来自于" + socket.getInetAddress().getHostAddress() + "的连接");

            //3. 接收数据
            is = socket.getInputStream();
            byte[] buffer = new byte[5];
            int len;
            ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 内部维护了一个byte[]
            while ((len = is.read(buffer)) != -1) {
                // 错误的,可能会出现乱码。
//                String str = new String(buffer, 0, len);
//                System.out.print(str);

                // 正确的
                baos.write(buffer, 0, len);
            }

            System.out.println(baos.toString());

            System.out.println("\n数据接收完毕");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4、关闭Socket、ServerSocket、流
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (serverSocket != null)
                    serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

客户端发送文件给服务端,服务端将文件保存在本地。

java 复制代码
public void client() {
        Socket socket = null;
        FileInputStream fis = null;
        OutputStream os = null;
        try {
            // 1. 创建Socket
            // 指明对方(即为服务器端)的ip地址和端口号
            InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
            int port = 9090;
            socket = new Socket(inetAddress, port);

            // 2. 创建File的实例、FileInputStream的实例
            File file = new File("pic.jpg");
            fis = new FileInputStream(file);
            // 3. 通过Socket,获取输出流
            os = socket.getOutputStream();

            // 4. 读写数据
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }

            System.out.println("数据发送完毕");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 5. 关闭Socket和相关的流
            try {
                if (os != null)
                    os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void server() {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            //1. 创建ServerSocket
            int port = 9090;
            serverSocket = new ServerSocket(port);

            //2. 接收来自于客户端的socket:accept()
            socket = serverSocket.accept();

            //3. 通过Socket获取一个输入流
            is = socket.getInputStream();

            //4. 创建File类的实例、FileOutputStream的实例
            File file = new File("pic_copy.jpg");
            fos = new FileOutputStream(file);

            //5. 读写过程
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }

            System.out.println("数据接收完毕");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //6. 关闭相关的Socket和流
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (serverSocket != null)
                    serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

从客户端发送文件给服务端,服务端保存到本地。并返回"发送成功"给客户端。并关闭相应的连接。

java 复制代码
public void client() {
        Socket socket = null;
        FileInputStream fis = null;
        OutputStream os = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            // 1. 创建Socket
            // 指明对方(即为服务器端)的ip地址和端口号
            InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
            int port = 9090;
            socket = new Socket(inetAddress, port);

            // 2. 创建File的实例、FileInputStream的实例
            File file = new File("pic.jpg");
            fis = new FileInputStream(file);
            // 3. 通过Socket,获取输出流
            os = socket.getOutputStream();

            // 4. 读写数据
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }

            System.out.println("数据发送完毕");

            // 客户端表明不再继续发送数据
            socket.shutdownOutput();

            //5. 接收来自于服务器端的数据
            is = socket.getInputStream();
            baos = new ByteArrayOutputStream();
            byte[] buffer1 = new byte[5];
            int len1;
            while ((len1 = is.read(buffer1)) != -1) {
                baos.write(buffer, 0, len1);
            }
            System.out.println(baos.toString());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6. 关闭Socket和相关的流
            try {
                baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (os != null)
                    os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void server() {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        FileOutputStream fos = null;
        OutputStream os = null;
        try {
            //1. 创建ServerSocket
            int port = 9090;
            serverSocket = new ServerSocket(port);

            //2. 接收来自于客户端的socket:accept()
            socket = serverSocket.accept();

            //3. 通过Socket获取一个输入流
            is = socket.getInputStream();

            //4. 创建File类的实例、FileOutputStream的实例
            File file = new File("pic_copy.jpg");
            fos = new FileOutputStream(file);

            //5. 读写过程
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }

            System.out.println("数据接收完毕");
            //6. 服务端发送数据给客户端
            os = socket.getOutputStream();
            os.write("你的图片很漂亮,我接收到了".getBytes());


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //7. 关闭相关的Socket和流
            try {
                if (os != null)
                    os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (serverSocket != null)
                    serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
相关推荐
想成为优秀工程师的爸爸2 小时前
第三十篇技术笔记:郭大侠学UDS - 人有生老三千疾,望闻问切良方医
网络·笔记·网络协议·tcp/ip·信息与通信
橙子也要努力变强2 小时前
信号捕捉底层机制-机理篇2
linux·服务器·c++
秋92 小时前
MySQL 8.0.46 全平台安装与配置详解(Windows/Linux/macOS)
linux·windows·mysql
数智工坊3 小时前
【SAM-DETR论文阅读】:基于语义对齐匹配的DETR极速收敛检测框架
网络·论文阅读·人工智能·深度学习·transformer
小康小小涵3 小时前
基于ESP32S3实现无人机RID模块底层源码编译
linux·开发语言·python
CQU_JIAKE3 小时前
4.28~4.30【Q】
linux·运维·服务器
左手厨刀右手茼蒿3 小时前
Linux 内核中的设备驱动开发:从字符设备到网络设备
linux·嵌入式·系统内核
先知后行。3 小时前
Linux 设备模型和platform平台
linux·运维·服务器
lzh200409193 小时前
深入理解进程:从PCB内核结构到写时拷贝的底层实战
linux·c++