Java 网络编程详解

一、Java网络编程

一)概述

  • 计算机网络

    • 连接分散计算机设备以实现信息传递的系统。
    • 作用是将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递
  • 网络编程的目的

    • 使用套接字来达到进程间相互通信
  • 网络编程的要素

    • IP地址
      • 找到一个主机
    • 端口号
      • 定位到该主机的某个资源
    • 网络通信协议,UDP/TCP
  • 两种架构

    • 网页编程:B/S架构
    • 网络编程:TCP/IP C/S架构
  • 网络通信的协议

    • TCP/IP参考模型

在这里插入图片描述

二)IP

  • InetAddress类

  • 作用

    • 唯一定位网络中一台计算机的位置
    • 本机
      • 127.0.0.1 或 localhost
  • IP地址的分类

    • ipv4/ipv6
      • ipv4,4个字节
      • ipv6,6个字节
    • 广域网/局域网
      • 广域网,就是互联网
      • 局域网,公司或组织内部自己使用的网络
  • 域名

    • 因为IP地址记忆起来不方便,所以使用域名代替IP地址,便于记忆
  • 代码练习

    • 使用InetAddress类查询本机及百度的IP地址
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    public class InetAddressTest {
        public static void main(String[] args) {
            try {
                //查询默认主机(本机)的IP地址并打印
                InetAddress address1 = InetAddress.getByName("127.0.0.1");//根据ip地址的到一个ip地址对象
                System.out.println(address1);//打印ip对象的存储的ip
    
                //查询本机的ip地址并打印
                InetAddress localHost1 = InetAddress.getByName("localhost");
                System.out.println(localHost1);
    
                //查询本机的ip地址并打印
                InetAddress localHost2 = InetAddress.getLocalHost();
                System.out.println(localHost2);
    
                //查询百度的ip地址并打印
                InetAddress baiduAddress = InetAddress.getByName("www.baidu.com");
                System.out.println(baiduAddress);
    
                //常用的一些方法
                System.out.println(baiduAddress.getCanonicalHostName());//得到规范的主机名
                System.out.println(baiduAddress.getHostAddress());//得到ip地址
                System.out.println(baiduAddress.getHostName());//得到域名
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
    }

四)端口

  • InetSocketAddress

  • 作用

    • 表示计算机上的一个程序的进程,不同的进程有不同的端口号,用来区分软件
    • 规定TCP协议下有065535个,UDP协议下有065535个。不同协议间端口号可以重复,单个协议间,端口号不能冲突
  • 端口分类

    • 公有端口
      • HTTP:80
      • HTTPS:443
      • FTP:21
      • Telent:23
    • 程序注册端口
      • MySQL:3306
      • Oracel:1521
    • 动态、私有端口
      • 49152~65535
  • 在DOS窗口查看端口

    • netstat -ano
      • 查看所有的端口
    • netstat -ano|findstr “端口号”
      • 查看指定的端口
    • tasklist|findstr “端口号”
      • 查看指定端口的进程
  • 代码练习

    • 套接字地址的练习
    import java.net.InetSocketAddress;
    
    public class InetSocketAddressTest {//端口号,套接字地址的练习
        public static void main(String[] args) {
            InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);//使用默认IP创建套接字地址对象
            System.out.println(socketAddress.toString());//打印套接字地址的主机号+端口号
            InetSocketAddress localSocketAddress = new InetSocketAddress("local", 8080);//使用本机名创建套接字地址对象
            System.out.println(localSocketAddress);//打印套接字地址的主机号+端口号
    
            System.out.println(socketAddress.getAddress());//打印套接字地址的地址
            System.out.println(socketAddress.getHostName());//打印套接字地址的主机名
            System.out.println(socketAddress.getPort());//打印套接字地址的端口号
        }
    }

五)通信协议

  • 作用

    • 其实就是一种传输信息的一种约定,实现传输数据与接收数据的规范化
    • 涉及到速率、传输码率、代码结构、传输控制等
  • TCP/IP参考模型
    在这里插入图片描述

  • TCP与UDP对比

    • TCP:用户传输协议

      • 类比于打电话,传输双方必须连接通,确认开始之后才能通信
      • 稳定,要连接
      • 有严格的连接与断开连接:三次握手、四次挥手
      三次握手:保证稳定连接
      A:我要连接了
      B:你连接吧
      A:好的,我连接上了
      
      四次挥手:断开连接
      A:我要断开连接了
      B:你断吧
      B:你断开了吗(再次确认一下)
      A:我已经断开了
      
      • 有明确的客户端和服务端
      • 传输完成时断开连接,效率低
    • UDP:用户数据报协议

      • 类比于发短信,只管发就行
      • 不稳定、不连接
      • 客户端与服务端无明确的区分
      • 不用等待连接,直接发

六)TCP

1. 传输消息
  • 服务器端

    • 建立服务的端口,ServerSocket类
    • 等待用户的连接,accept()方法
    • 接受用户的消息,getInputStream()方法
    • 代码练习
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class MessageServer {//接收消息的服务器端
    
        public static void main(String[] args) {
            //定义局部变量
            ServerSocket serverSocket = null;
            Socket socket = null;
            InputStream inputStream = null;
            ByteArrayOutputStream outputStream = null;
    
            try {
                serverSocket = new ServerSocket(9999);//创建一个服务器套接字对象,打开对应的端口
                while (true) {
                    socket = serverSocket.accept();//得到客户端的连接
                    inputStream = socket.getInputStream();//得到客户端的输入流
    
                    outputStream = new ByteArrayOutputStream();//创建一个字节数组输出流
    
                    //将客户端的输入流读取到字节数组输出流中
                    byte[] bytes = new byte[1024 * 8];
                    int len;
                    while ((len = inputStream.read(bytes)) != -1) {
                        outputStream.write(bytes, 0, len);
                    }
                    System.out.println(outputStream); //将输出流中的内容打印到控制台上
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {//从下往上依次关闭资源
                if (outputStream != null) {
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (inputStream != null) {
                    try {
                        inputStream.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();
                    }
                }
            }
        }
    }
  • 客户端

    • 连接服务器,Socket类,需要服务器的ip与端口号
    • 发送消息,getOutputStream()方法
    • 代码练习
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    
    public class MessageClient {//传输消息的客户端
    
        public static void main(String[] args) {
            InetAddress serverAddress = null;//服务器地址对象
            Socket socket = null;//套接字连接对象
            OutputStream outputStream = null;//输出流对象
    
            try {
                serverAddress = InetAddress.getByName("127.0.0.1");//服务器地址对象
                int port = 9999;//服务器端口号
                socket = new Socket(serverAddress, port);//根据指定的IP地址与端口号创建一个套接字连接
    
                outputStream = socket.getOutputStream();//输出流对象
                outputStream.write("客户端发来的消息".getBytes());//客户端发出的消息
            } catch (IOException e) {
                e.printStackTrace();
            } finally {//资源释放
                if (outputStream != null) {
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
2. 文件上传
  • 服务器端
    • 代码实现
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class FileServer {//文件传输服务器
    
    public static void main(String[] args) {
        ServerSocket serverSocket = null;//声明变量
        Socket socket = null;
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            serverSocket = new ServerSocket(9090);//创建服务器,打开端口
            socket = serverSocket.accept();//得到客户端的连接
            inputStream = socket.getInputStream();//得到客户端的文件输入流

            outputStream = new FileOutputStream(new File("receive.png"));//创建文件输出流
            byte[] bytes = new byte[1024 * 8];//将客户端输入流中的数据读取到输出流中
            int len;
            while ((len = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, len);
            }

            //告知客户端已接受完成
            socket.getOutputStream().write("我已经接收完了,你可以断开了".getBytes());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {//释放资源
            try {
                outputStream.close();
                inputStream.close();
                socket.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 客户端
    • 代码实现
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class FileClient {//文件传输客户端

    public static void main(String[] args) {
        Socket socket = null;//声明变量
        OutputStream outputStream = null;
        FileInputStream fileInputStream = null;
        InputStream inputStream = null;
        ByteArrayOutputStream arrayOutputStream = null;
        try {
            socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);//创建与服务器指定端口的连接

            outputStream = socket.getOutputStream();//得到连接的输出流

            //得到要传输文件的输入流
            fileInputStream = new FileInputStream(new File("1575180473779.png"));

            //将要传输文件写出到连接的输出流中
            byte[] bytes = new byte[1024 * 8];
            int len;
            while ((len = fileInputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, len);
            }

            socket.shutdownOutput();//告知服务器,客户端已经传输完了

            inputStream = socket.getInputStream();//得到服务器的消息输入流
            arrayOutputStream = new ByteArrayOutputStream();//创建输出流
            byte[] bytes1 = new byte[1024 * 8];//将服务器的消息输入流写入输出流中
            int len1;
            while ((len1 = inputStream.read(bytes1)) != -1) {
                arrayOutputStream.write(bytes1, 0, len1);
            }

            System.out.println(arrayOutputStream);//打印输出流
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//关闭资源
            try {
                arrayOutputStream.close();
                inputStream.close();
                socket.close();
                outputStream.close();
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
3. Tomcat

七)UDP

  • 不需要连接,需要知道对方的Ip地址和端口号
1. 发送消息
  • 发送端
    • 代码示例
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class MessageSender {//消息发送端

    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket();//创建一个连接

        InetAddress localhost = InetAddress.getByName("127.0.0.1");//连接地址
        int port = 9090;//连接端口
        String msg = "你好啊,服务器";//发送消息的内容

        //将要发送的消息内容、消息长度、接收方ip地址和端口号打包起来
        DatagramPacket packet = new DatagramPacket(msg.getBytes(), msg.getBytes().length, localhost, port);

        socket.send(packet);//将包发送出去

        socket.close();//关闭资源
    }
}
  • 接收端
    • 代码示例
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class MessageReceiver {//消息接收端

    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(9090);//将端口号9090开放

        byte[] bytes = new byte[1024 * 8];
        DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);//创建数据接受包

        socket.receive(packet);//将端口中接收的数据放进数据接受包中

        System.out.println(packet.getAddress().getHostAddress());//打印消息发送方信息

        System.out.println(new String(packet.getData()));//打印数据接受包中的消息

        socket.close();//关闭连接
    }
}
2. 咨询
  • 双发都可以收发消息

  • 发送方

    • 代码练习
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class ConsultingSender {//咨询发送方

    public static void main(String[] args) throws Exception {

        DatagramSocket socket = new DatagramSocket(8080);//创建一个套接字,打开8080端口
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//从键盘读取数据

        while (true) {

            synchronized ("A") {
                InetSocketAddress socketAddress = new InetSocketAddress("localhost", 9090);//创建连接

                //发消息
                byte[] senderBytes = reader.readLine().getBytes();//从键盘读取数据,将数据转换为字节
                DatagramPacket senderPacket = new DatagramPacket(senderBytes, 0, senderBytes.length, socketAddress);//将要发送的数据打包
                socket.send(senderPacket);//发送包
                if (reader.readLine().equals("bye")) {//当输入"bye"时,聊天结束
                    break;
                }

                //接收消息
                byte[] ReceiveBytes = new byte[1024 * 8];
                DatagramPacket ReceivePacket = new DatagramPacket(ReceiveBytes, 0, ReceiveBytes.length, socketAddress);//创建自己的接受包
                socket.receive(ReceivePacket);//将接收到的包放进自定义的包中
                String receiveData = new String(ReceivePacket.getData());//得到包中的数据
                System.out.println("医生:\t" + receiveData);//打印包中的数据
                if (receiveData.equals("bye")) {
                    break;
                }
            }
        }
        socket.close();//关闭资源
    }
}
  • 接收方
    • 代码练习
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class ConsultingReceiver {//咨询接收方(医生)

    public static void main(String[] args) throws Exception {

        DatagramSocket socket = new DatagramSocket(9090);//打开9090端口
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//从键盘读取数据

        while (true) {

            InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);//创建连接

            //发送消息
            byte[] readerBytes = reader.readLine().getBytes();//得到键盘的输入
            DatagramPacket senderPacket = new DatagramPacket(readerBytes, 0, readerBytes.length, socketAddress);//将键盘输入的数据打包
            socket.send(senderPacket);//发送包
            if (reader.readLine().equals("bye")) {
                break;
            }

            //接收消息
            byte[] ReceiveBytes = new byte[1024 * 8];
            DatagramPacket ReceivePacket = new DatagramPacket(ReceiveBytes, 0, ReceiveBytes.length, socketAddress);//创建一个接受包,用来接收另一方传来的数据
            socket.receive(ReceivePacket);//将接收到的包放进packed包中
            String receiveData = new String(ReceivePacket.getData());//得到包中的数据
            System.out.println("咨询者:\t" + new String(ReceivePacket.getData()));//打印包中的数据
            if (receiveData.equals("bye")) {
                break;
            }
        }
        socket.close();
    }
}

八)URL

  • 作用
    • 统一资源定位器,用来定位互联网上的额某一个资源
  • 格式
    • 协议: //ip协议: 端口/项目名/资源
  • 代码练习
    • 下载网络上的某一个音频/视频资源
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class URLExercises {//URL练习,使用URL下载网络上的某一个资源

    public static void main(String[] args) throws Exception {
        //网络资源URL
        String fileURL = "https://m701.music.126.net/20191205191532/241ad6725dfd6021a4860765cd9e4b34/jdyyaac/040c/515a/0053/3fac72c8b9f0dd09f05879e7155052fa.m4a";
        URL url = new URL(fileURL);//封装网络资源URL
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();//得到URL连接
        InputStream inputStream = urlConnection.getInputStream();//得到网络资源的输入流

        String finalPath = "C:\\Users\\北风\\Desktop\\像风一样3.m4a";//目标路径
        FileOutputStream outputStream = new FileOutputStream(new File(finalPath));//目标路径输出流

        //将网络资源输入流写入目标路径输出流
        byte[] bytes = new byte[1024 * 8];
        int len;
        while ((len = inputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, len);
        }

        //释放资源
        outputStream.close();
        inputStream.close();
        urlConnection.disconnect();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值