Java-网络编程

网络通信协议:

网络通信协议有很多种,目前应用最广泛的是TCP/IP协议(Transmission Control Protocol/Internet Protocol,传输控制协议/英特网互联协议)、UDP协议(User Datagram Protocol,用户数据报协议)和一些其他的协议。下面我们学习的协议,主要是基于TCP/IP协议中的内容。

基于TCP/IP的参考模型将协议分成四个层次,如下图所示:

image-20210511002557435

TCP/IP协议中的一共有四层,分别是链路层、网络层、传输层应用层

实现网络通信,需要通信双方的地址:ip、端口号等数据。

一般的网络通信协议:http、ftp、smtp、tcp、udp等。

TCP/IP参考模型:

网络编程中的要素:ip和端口号;网络通信协议

  • 在JDK中,提供了一个与IP地址相关的InetAddress类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法:
//测试IP:
public class IP {
    public static void main(String[] args) {
        try {
            //查询本机IP地址:
            InetAddress InetAddress1 = InetAddress.getByName("192.168.239.1");
            System.out.println(InetAddress1);
            System.out.println("获取本地主机地址:" + InetAddress.getByName("localhost"));
            System.out.println("获取本机IP地址:" + InetAddress.getLocalHost());

            //查询网站IP地址:
            InetAddress InetAddress2 = InetAddress.getByName("www.bilibili.com");
            System.out.println(InetAddress2);

            System.out.println(InetAddress2.getAddress());
            System.out.println(InetAddress2.getHostName());
            System.out.println(InetAddress2.getCanonicalHostName());
            System.out.println(InetAddress2.getHostAddress());

        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}
//查询端口号:
public class TestInetSocketAddress {
    public static void main(String[] args) {
        InetSocketAddress inetSocketAddress1 = new InetSocketAddress("127.0.0.1",8080);
        InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost",8080);
        System.out.println(inetSocketAddress1);
        System.out.println(inetSocketAddress2);

        System.out.println(inetSocketAddress1.getPort());
        System.out.println(inetSocketAddress1.getAddress());
        System.out.println(inetSocketAddress1.getHostName());
        System.out.println(inetSocketAddress1.getHostString());
    }
}

通信协议

在介绍TCP/IP结构时,提到传输层的两个重要的高级协议,分别是UDP和TCP。

  • UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。例如:发短信;
  • TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。;例如:打电话;

TCP:用户传输协议

TCP通信同UDP通信一样,也能实现两台计算机之间的通信,但TCP通信的两端需要创建socket对象。而且服务端必须先启动,再启动客户端;

在JDK中提供了两个用于实现TCP程序的类,一个是ServerSocket类,用于表示服务器端;一个是Socket类,用于表示客户端。通信时,首先要创建代表服务器端的ServerSocket对象,创建该对象相当于开启一个服务,此服务会等待客户端的连接;然后创建代表客户端的Socket对象,使用该对象向服务器端发出连接请求,服务器端响应请求后,两者才建立连接,开始通信。

  • 三次握手,四次挥手(最少保持三次数据回应,保证稳定连接)
  • 客户端、服务端
  • 传输完成,当即释放链接,效率低

TCP测试:

​ 1)客户端

  • 连接服务器Socket

  • 发送消息

    2)服务端

  • 建立服务的端口 ServerSocket

  • 等待用户连接 accept

  • 接收用户消息

//测试一:
//客户端
public class TcpClientDemo01 {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream os = null;
        try {
            //1、获取服务器的端口号:
//            InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
//            int port = 9999;
            //2、创建一个socket连接:
//            socket = new Socket(inetAddress,port);
            socket = new Socket("127.0.0.1",9999);
//            Socket socket1 = new Socket();
//            socket1.connect(new InetSocketAddress("127.0.0.1",9999));
            //3、发送消息IO:
            os = socket.getOutputStream();
            os.write("this is socket message!".getBytes());
            System.out.println("message ==> server");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

//服务端
public class TcpServerDemo01 {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream bais = null;
        //服务端需要设置一个端口号:ServerSocket()
        try {
            //1、设置一个地址:
            serverSocket = new ServerSocket(9999);
            //2、客户端连接过来:accept()
            socket = serverSocket.accept();
            //3、收取消息:(获取输入流)
            is = socket.getInputStream();
            //定义管道流写出数据:  ByteArrayOutputStream() 不会发生字符乱码现象;
            bais = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int leng;
            while ((leng = is.read(bytes)) != -1){
                bais.write(bytes,0,leng);
            }
            System.out.println(bais.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bais != null){
                try {
                    bais.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
//测试二:
//客户端:
public class TcpClientDemo02 {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream os = null;
        FileInputStream fis = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            //1、连接到服务端:
            socket = new Socket(InetAddress.getByName("127.0.0.1"),9000);
            //2、输出文件到服务端:
            os = socket.getOutputStream();
            fis = new FileInputStream(new File("img1.jpg"));
            byte[] bytes = new byte[1024];
            int leng;
            while ((leng = fis.read(bytes)) != -1){
                os.write(bytes,0,leng);
            }
            
            //通知服务器已经发送完毕:
            socket.shutdownOutput(); //传输完毕了

            //3、确定服务器接收完毕,断开连接:
            is = socket.getInputStream();
            baos = new ByteArrayOutputStream();
            byte[] bytes1 = new byte[1024];
            int leng1;
            while ((leng1 = is.read(bytes1)) != -1){
                baos.write(bytes1,0,leng1);
            }
            System.out.println(baos.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (baos != null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

//服务端:
public class TcpServerDemo02 {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            //1、设置服务端的端口号:
            serverSocket = new ServerSocket(9000);
            //2、连接到客户端:(阻塞式监听,会一直等待客户端连接)
            socket = serverSocket.accept();
            //3、接收客户发送的信息:
            is = socket.getInputStream();           		  //输入
            fos = new FileOutputStream("clientimg2.jpg");     //输出
            byte[] bytes = new byte[1024];
            int leng;
            while ((leng = is.read(bytes)) != -1){
                fos.write(bytes,0,leng);
            }
            //4、通知客户端接收完毕:
            OutputStream os = socket.getOutputStream();
            os.write("the message over".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

UDP:用户数据报协议

UDP是一种面向无连接的协议,因此,在通信时发送端和接收端不用建立连接。

UDP通信发送和接收的数据也需要使用“集装箱”进行打包,为此JDK中提供了一个DatagramPacket类,该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。其中发送端可以使用send()发送包,接收端可以使用receive()接收包。

  • 不需要连接,不稳定
  • 客户端、服务端:没有明确的界限
  • 无需对面用户准备好,即发即收
  • 发送数据结束时无需释放资源,开销小,速度快
//不需要连接服务器,可以直接发送消息:DatagramSocket()、DatagramPacket()
//发送端:
public class UdpClientDemo01 {
    public static void main(String[] args) {
        DatagramSocket socket = null;
        try {
            //1、建立一个Socket:
            socket = new DatagramSocket();

            //2、建立包:
            String msg = "服务器!服务器!";
            InetAddress localhost = InetAddress.getByName("localhost");
            int port = 9090;

            //需要发送的数据,数据的起始位置,数据的结束位置,ip地址,端口号
            DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);

            //3、发送包:
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null){
                socket.close();
            }
        }
    }
}

//接收端:
public class UdpServerDemo01 {
    public static void main(String[] args) {
        DatagramSocket socket = null;
        try {
            //开放端口:
            socket = new DatagramSocket(9090);
            //接收数据包:
            byte[] bytes = new byte[1024];
            DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length);

            //阻塞接收:
            socket.receive(packet);

            System.out.println(packet.getAddress().getHostAddress());
            System.out.println(new String(packet.getData()));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null){
                socket.close();
            }
        }
    }
}
//测试:定义从控制台输入数据到接收端的程序:
//发送端:
public class UdpChatSend {
    public static void main(String[] args) throws Exception {
        //1、建立一个Socket:
        DatagramSocket socket = new DatagramSocket();

        //2、定义发送的数据: 从控制台读取数据
        BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
        String str = bfr.readLine();
        while (true){
            DatagramPacket packet = new DatagramPacket(str.getBytes(),0,str.getBytes().length,
                    new InetSocketAddress("localhost",6666));
            socket.send(packet);
            if ("bye".equals(str)){			//如果输入bye,则会退出
                break;
            }
        }
        bfr.close();
        socket.close();
    }
}

//接收端:
public class UdpChatReceive {
    public static void main(String[] args) throws Exception {
        //1、开发端口:
        DatagramSocket socket = new DatagramSocket(6666);
        //2、接收数据包:
       while (true){
           byte[] bytes = new byte[1024];
           DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length);
           socket.receive(packet);     //阻塞接收数据
           //获取接收的数据:
            byte[] data = packet.getData();
            String datas = new String(data,0,data.length);
            //打印输出传输过来的数据:
           System.out.println(datas);
           //断开连接:
           if (datas.trim().equals("bye")){
                break;
            }
       }
        socket.close();
    }
}

URL类

URL:统一资源定位符,他表示Internet上某一资源的地址。

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

<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表

例如:http://localhost:8080/vx/doc.jsp?username=vx&passwd=123#a

!!:片段名即锚点,例如浏览淘宝,直接定位到第几页。

参数列表格式:参数名=参数值&参数名=参数值.....

在JDK中,URL提供了以下方法:

public class TestUrl {
    public static void main(String[] args) throws Exception {
        URL url  = new URL("http://localhost:8080/vx/doc.jsp?username=vx&passwd=123#a");

        System.out.println("获取与此url关联的协议的默认端口:" + url.getDefaultPort());
        System.out.println("端口号后面的内容:" + url.getFile());
        System.out.println("主机名:" + url.getHost());
        System.out.println("路径:" + url.getPath()); // 端口号后,参数前的内容
        System.out.println("端口:" + url.getPort());
        System.out.println("协议:" + url.getProtocol());
        System.out.println("参数部分:" + url.getQuery());
        System.out.println("锚点:" + url.getRef());
    }
}
//使用URL下载文件在存储到本地:
public class TestUrlP {
    public static void main(String[] args) throws Exception {
        //1、下载地址:
        URL url = new URL("需要下载的网络资源地址");
        //2、连接到这个资源:
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        //获取连接:
        connection.connect();
        //3、输入写出流:
        InputStream is = connection.getInputStream();
        FileOutputStream fos = new FileOutputStream("保存资源名字.后缀");
        byte[] bytes = new byte[1024];
        int leng;
        while ((leng = is.read(bytes)) != -1){
            fos.write(bytes,0,leng);
        }
        //3、关闭流
        fos.close();
        is.close();
        connection.disconnect();
    }
}
posted @ 2021-05-12 23:37  VXZX  阅读(97)  评论(0)    收藏  举报