美文网首页
Java学习总结之网络操作

Java学习总结之网络操作

作者: Steven1997 | 来源:发表于2018-09-23 17:54 被阅读55次

    概述

    网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
    java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。
    Java支持下列常用网络操作:

    • InetAddress:用于表示网络上的硬件资源,即 IP 地址;
    • URL:统一资源定位符;
    • Socket:使用 TCP 协议实现网络通信。TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
    • Datagram:使用 UDP 协议实现网络通信。UDP 是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。

    下面我们分别来学习:

    InetAddress

    java.net.InetAddress类是Java对IP地址(包括IPv4和IPv6)的高层表示。大多数其他网络类都要用到这个类,包括Socket,ServerSocket,URL,DatagramSocket,DatagramPacket等。一般地讲,它包括一个主机名和一个IP地址。
    主机名到 IP 地址的解析 通过使用本地机器配置信息和网络命名服务(如域名系统(Domain Name System,DNS)和网络信息服务(Network Information Service,NIS))来实现。
    反向名称解析 意味着对于任何 IP 地址,都返回与 IP 地址关联的主机。
    InetAddress 类提供将主机名解析为其 IP 地址(或反之)的方法。

    • static InetAddress[] getAllByName(String host)
      在给定主机名的情况下,根据系统上配置的名称服务返回所有的 IP 地址。
    • static InetAddress getByAddress(byte[] addr)
      在给定原始 IP 地址的情况下,返回 InetAddress 对象。
    • static InetAddress getByAddress(String host, byte[] addr)
      根据提供的主机名和 IP 地址创建 InetAddress。
    • static InetAddress getByName(String host)
      在给定主机名的情况下确定主机的 IP 地址。
    • String getCanonicalHostName()
      获取此 IP 地址的完全限定域名。
    • String getHostAddress()
      返回 IP 地址字符串,比如192.168.1.1
    • String getHostName()
      获取此 IP 地址的主机名。比如 www.baidu.com
    • static InetAddress getLocalHost()
      返回本地主机。
    • boolean isReachable(int timeout)
      测试是否可以达到该地址。

    URL

    URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者FTP地址。
    URL可以分为如下几个部分:
    protocol://host:port/path?query#fragment
    实例:http://www.runoob.com/index.html?language=cn#j2se

    URL 各部分解析:
    protocol(协议):可以是 http、https、ftp 、file等,上面例子是http
    host(主机):www.runoob.com
    port(端口号):80 ,以上URL实例并未指定端口,因为 HTTP 协议默认的端口号为 80。
    path(文件路径):/index.html
    query(请求参数):language=cn
    fragment(定位位置):j2se,定位到网页中 id 属性为 j2se 的 HTML 元素位置 。

    URL 类方法

    在java.net包中定义了URL类,该类用来处理有关URL的内容。对于URL类的创建和使用,下面分别进行介绍。
    java.net.URL提供了丰富的URL构建方式,并可以通过java.net.URL来获取资源。



    URL类中包含了很多方法用于访问URL的各个部分,具体方法及描述如下:



    以上实例演示了使用java.net的URL类获取URL的各个部分参数:
    URLDemo.java

    import java.net.*;
    import java.io.*;
     
    public class URLDemo
    {
       public static void main(String [] args)
       {
          try
          {
             URL url = new URL("http://www.runoob.com/index.html?language=cn#j2se");
             System.out.println("URL 为:" + url.toString());
             System.out.println("协议为:" + url.getProtocol());
             System.out.println("验证信息:" + url.getAuthority());
             System.out.println("文件名及请求参数:" + url.getFile());
             System.out.println("主机名:" + url.getHost());
             System.out.println("路径:" + url.getPath());
             System.out.println("端口:" + url.getPort());
             System.out.println("默认端口:" + url.getDefaultPort());
             System.out.println("请求参数:" + url.getQuery());
             System.out.println("定位位置:" + url.getRef());
          }catch(IOException e)
          {
             e.printStackTrace();
          }
       }
    }
    

    结果如下:
    URL 为:http://www.runoob.com/index.html?language=cn#j2se
    协议为:http
    验证信息:www.runoob.com
    文件名及请求参数:/index.html?language=cn
    主机名:www.runoob.com
    路径:/index.html
    端口:-1
    默认端口:80
    请求参数:language=cn
    定位位置:j2se

    URLConnections 类方法

    openConnection() 返回一个 java.net.URLConnection。
    例如:

    • 如果你连接HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象。
    • 如果你连接的URL为一个 JAR 文件, openConnection() 方法将返回 JarURLConnection 对象。

    URLConnection 方法列表如下:



    以下实例中URL采用了HTTP 协议。 openConnection 返回HttpURLConnection对象,并通过该对象得到URL的输入流,读取字节流数据:

    public static void main(String[] args) throws IOException {
    
        URL url = new URL("http://www.baidu.com");
    
        /* 字节流 */
        InputStream is = url.openStream();
    
        /* 字符流 */
        InputStreamReader isr = new InputStreamReader(is, "utf-8");
    
        /* 提供缓存功能 */
        BufferedReader br = new BufferedReader(isr);
    
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    
        br.close();
    }
    

    Socket 编程

    套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
    当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。
    java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
    以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:

    • 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。

    • 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。

    • 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。

    • Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。

    • 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。

    连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流
    TCP 是一个全双工的通信协议,因此数据可以通过两个数据流在同一时间发送。以下是一些类提供的一套完整的有用的方法来实现 socket。

    ServerSocket 类的方法

    服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求
    ServerSocket 类有四个构造方法:


    如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。

    这里有一些 ServerSocket 类的常用方法:


    Socket 类的方法

    java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而服务器获得一个 Socket 对象则通过 accept() 方法的返回值。

    Socket 类有五个构造方法:


    当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。
    下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法:


    Socket 客户端实例

    如下的 GreetingClient 是一个客户端程序,该程序通过 socket 连接到服务器并发送一个请求,然后等待一个响应。
    GreetingClient.java

    import java.net.*;
    import java.io.*;
     
    public class GreetingClient
    {
       public static void main(String [] args)
       {
          String serverName = args[0];
          int port = Integer.parseInt(args[1]);
          try
          {
             System.out.println("连接到主机:" + serverName + " ,端口号:" + port);
             Socket client = new Socket(serverName, port);
             System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
             OutputStream outToServer = client.getOutputStream();
             DataOutputStream out = new DataOutputStream(outToServer);
     
             out.writeUTF("Hello from " + client.getLocalSocketAddress());
             InputStream inFromServer = client.getInputStream();
             DataInputStream in = new DataInputStream(inFromServer);
             System.out.println("服务器响应: " + in.readUTF());
             client.close();
          }catch(IOException e)
          {
             e.printStackTrace();
          }
       }
    }
    

    Socket 服务端实例

    如下的GreetingServer 程序是一个服务器端应用程序,使用 Socket 来监听一个指定的端口。
    GreetingServer.java

    import java.net.*;
    import java.io.*;
     
    public class GreetingServer extends Thread
    {
       private ServerSocket serverSocket;
       
       public GreetingServer(int port) throws IOException
       {
          serverSocket = new ServerSocket(port);
          serverSocket.setSoTimeout(10000);
       }
     
       public void run()
       {
          while(true)
          {
             try
             {
                System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");
                Socket server = serverSocket.accept();
                System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
                DataInputStream in = new DataInputStream(server.getInputStream());
                System.out.println(in.readUTF());
                DataOutputStream out = new DataOutputStream(server.getOutputStream());
                out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "\nGoodbye!");
                server.close();
             }catch(SocketTimeoutException s)
             {
                System.out.println("Socket timed out!");
                break;
             }catch(IOException e)
             {
                e.printStackTrace();
                break;
             }
          }
       }
       public static void main(String [] args)
       {
          int port = Integer.parseInt(args[0]);
          try
          {
             Thread t = new GreetingServer(port);
             t.run();
          }catch(IOException e)
          {
             e.printStackTrace();
          }
       }
    }
    

    编译以上两个 java 文件代码,并执行以下命令来启动服务,使用端口号为 6066:

    $ javac GreetingServer.java 
    $ java GreetingServer 6066
    等待远程连接,端口号为:6066...
    

    新开一个命令窗口,执行以上命令来开启客户端:

    $ javac GreetingClient.java 
    $ java GreetingClient localhost 6066
    连接到主机:localhost ,端口号:6066
    远程主机地址:localhost/127.0.0.1:6066
    服务器响应: 谢谢连接我:/127.0.0.1:6066
    Goodbye!
    

    Datagram

    UDP和TCP的特点

    用户数据报协议 UDP(User Datagram Protocol)无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信,效率高但不可靠。事实上,可以用UDP实现一个可靠的文件传输协议,而且很多人确实是这样做的:网络文件系统,简单FTP都使用了UDP协议。在这些协议中由应用程序来负责可靠性
    传输控制协议 TCP(Transmission Control Protocol)面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一),效率低但安全可靠。

    java中对UDP编程的支持

    java中的UDP实现分为两个类:DatagramPacketDatagramSocket。DatagramPacket类将数据字节填充到UDP包中,这称为数据报。 DatagramSocket来发送这个包。要接受数据,可以从DatagramSocket中接受一个 DatagramPack对象,然后从该包中读取数据的内容。
    这种职责的划分与TCP使用的SocketServerSocket有所不同。首先,UDP没有两台主机间唯一连接的概念,它不需要知道对方是哪个远程主机。它可以从一个端口往多个主机发送信息,但是TCP是无法做到的。其次,TCP socket把网络连接看作是流:通过从Socket得到的输入和输出流来收发数据。UDP不支持这一点,你处理总是单个数据包。填充在一个数据报中的所有数据会以包的形式进行发送,这些数据要么作为一个组要么全部接收,要么全部丢弃。一个包不一定与下一个包相关。给定两个包,没有办法知道哪个先发哪个后发。对于流来说,必须提供数据的有序队列,与之不同,数据报会尽可能快的蜂拥到接收方。

    DatagramSocket类

    java.net.DatagramSocket 此类表示用来发送和接收数据报包的套接字

    该类主要有下列构造方法:

    • DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口。
    • DatagramSocket(int port, InetAddress laddr) 创建数据报套接字,将其绑定到指定的地址。

    常用的方法:

    • send(DatagramPacket p) 从此套接字发送数据报包。
    • receive(DatagramPacket p)从此套接字接收数据报包。
    • close() 关闭此数据报套接字。

    DatagramPacket类

    此类表示数据报包。

    构造方法(因为UDP是无连接的,所以在用于发送的数据包中附加目的地址,而用于接收的数据包不用加地址信息):

    • DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
      构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
    • DatagramPacket(byte[] buf, int length, InetAddress address, int port)
      构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
    • DatagramPacket(byte[] buf, int length)
      构造 DatagramPacket,用来接收长度为 length 的数据包。

    DatagramSocket 客户端实例

    UDPClient.java

    public class UDPClient {
        public static void main(String[] args) {
            try {
                //1.创建数据报套接字
                DatagramSocket datagramSocket =  new DatagramSocket(6666);
                //2.创建数据报包用于封装数据和目标地址
                String str="hello world!";
                byte[] content = str.getBytes();//将字符串转换为字节的数组
                DatagramPacket datagramPacket = new DatagramPacket(content, content.length,InetAddress.getLocalHost(), 9999);
                //3.调用send方法进行发送数据
                datagramSocket.send(datagramPacket);
                //4.释放资源
                datagramSocket.close();
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }
    }
    

    DatagramSocket 服务端实例

    UDPServer.java

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    /**
     * DatagramSocket(int port)
     * DatagramPacket(byte[] buf, int length)  构造 DatagramPacket,用来接收长度为 length 的数据包。
     * DataPacket类中方法:
     *     getData() 返回数据缓冲区。
     *  getLength()返回将要发送或接收到的数据的长度。
     *  getPort() 返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的
     *  getAddress()返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
     * 
     */
    public class UDPServer {
        public static void main(String[] args) {
            try {
                //1.创建数据报套接字
                DatagramSocket socket = new DatagramSocket(9999);
                //2.创建一个数据报包
                byte[] content = new byte[1024];
                DatagramPacket datagramPacket = new DatagramPacket(content,content.length);
                //3.调用receive方法接收数据包
                socket.receive(datagramPacket);
                //4.从数据报包中获取数据
                byte[] data=  datagramPacket.getData();//获取数据报包中的数据
                int length = datagramPacket.getLength();//
                InetAddress ip = datagramPacket.getAddress();
                int port = datagramPacket.getPort();
                System.out.println("内容:"+new String(data,0,length));
                System.out.println("数据长度:"+length);
                System.out.println("发送方的IP地址:"+ip);
                System.out.println("发送方的端口号:"+port);
                //5.释放资源
                socket.close();
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }
    }
    

    利用UDP实现聊天功能

    UdpChatClient.java

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    import java.util.Scanner;
    
    /**
     * 利用UDP实现聊天功能
     * @author Administrator
     *
     */
    public class UdpChatClient {
        public static void main(String[] args) {
            System.out.println("---------顾客---------");
            try {
                //1.创建数据报套接字
                DatagramSocket socket = new DatagramSocket(6666);
                Scanner input = new Scanner(System.in);
                while(true){
                    //2.获取用户输入
                    String message = input.next();
                    byte[] bs = message.getBytes();
                    //3.创建数据报包
                    DatagramPacket packet = new DatagramPacket(bs, bs.length, InetAddress.getByName("127.0.0.1"),8888);
                    //4.发送数据
                    socket.send(packet);
                    //接收数据
                    byte[] bs2 = new byte[1024];
                    DatagramPacket packet2 = new DatagramPacket(bs2, bs2.length);
                    socket.receive(packet2);//接收数据
                    byte[] serverMesage = packet2.getData();
                    String str=new String(serverMesage,0,serverMesage.length);
                    System.out.println("客服说:"+str);
                    if(message.equals("bye")){
                        break;
                    }
                }
                //释放资源
                socket.close();
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }
    }
    

    UdpChatServer.java

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    import java.util.Scanner;
    
    /**
     * 利用UDP实现聊天功能
     * @author Administrator
     *
     */
    public class UdpChatServer {
        public static void main(String[] args) {
            System.out.println("---------客服---------");
            try {
                //1.创建数据报套接字
                DatagramSocket socket = new DatagramSocket(8888);
                Scanner input = new Scanner(System.in);
                while(true){
                    //接收数据
                    byte[] bs2 = new byte[1024];
                    DatagramPacket packet2 = new DatagramPacket(bs2, bs2.length);
                    socket.receive(packet2);//接收数据
                    byte[] serverMesage = packet2.getData();
                    String str=new String(serverMesage,0,serverMesage.length);
                    System.out.println("顾客说:"+str);
                    
                    //2.获取用户输入
                    String message = input.next();
                    byte[] bs = message.getBytes();
                    //3.创建数据报包
                    DatagramPacket packet = new DatagramPacket(bs, bs.length, InetAddress.getByName("127.0.0.1"),6666);
                    //4.发送数据
                    socket.send(packet);
                    if(message.equals("bye")){
                        break;
                    }
                }
                //释放资源
                socket.close();
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }
    }
    

    相关文章

      网友评论

          本文标题:Java学习总结之网络操作

          本文链接:https://www.haomeiwen.com/subject/yjcxnftx.html