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();
            }
        }
    }
相关推荐
咖啡有点酷25 分钟前
Geo-Targeting 技术深度解析:IP定位与本地化投放实践
网络·技术分享
AOwhisky34 分钟前
Linux(CentOS)系统管理入门笔记(第四期)——文件系统(下篇):文件与目录操作实战——cpmvmkdirrmln
linux·运维·笔记·centos·云计算·文件系统
VidDown42 分钟前
在线视频下载器技术解析:原理、工具与合规实践
网络·音视频·实时音视频·视频编解码·视频下载
努力努力再努力wz44 分钟前
【高性能网络库与HTTP Server系列】:基于主从 Reactor 模型实现高性能 C++ 网络库与 HTTP Server
开发语言·网络·数据结构·数据库·c++·网络协议·http
岑梓铭1 小时前
考研408《操作系统》复习笔记,第四章《4.2.2 文件操作、文件共享、文件保护》
linux·考研·操作系统·文件系统·408
Mr.HeBoYan1 小时前
DPDK为什么越来越少使用rte_ring?——从Lock-Free到Run-to-Completion,重新理解现代DPDK架构演进(上)
linux·网络·算法·性能优化·架构·dpdk
z小猫不吃鱼2 小时前
06 权重幅值剪枝、剪枝后微调与稀疏网络训练:模型剪枝中的三个基本问题
网络·算法·剪枝
2301_780356702 小时前
全视通智慧医院解决方案:构建数智化医疗新生态
大数据·网络·人工智能
云栖梦泽2 小时前
从 IMX415 摄像头驱动理解 Media Controller 框架
linux·开发语言·c++·嵌入式硬件
纳兰青华2 小时前
CentOS Stream 9 下载与安装完全指南:为什么它是当前最稳妥的选择?
linux