Java网络编程基础 - Go语言中文社区

Java网络编程基础


一、Java网络编程

  网络编程在如今这样的网络时代是十分重要的,Java语言提供了丰富的类库来支持网络编程。这里将重点介绍Java.net中的类,充分了解认识Java网络编程的原理并深入学习各模块。在学习Java网络编程之前首先需要具备一定的网络知识:网络的层次结构,常见的网络协议(TCP/IP),IP地址端口号等等。需要学习了解这些内容,可以参考前面的文章。

二、主机地址和IP地址

  在进行网络访问时,每个主机都有IP地址,也有主机名(域名),为了便于处理与之相关的问题,Java.net包中提供了地址获取类InetAddress,当然还有对应的子类Inet4Address,Inet6Address,分别对应IPv4和IPv6。这里介绍InetAddress的基本用法。

  1、InetAddress对象

  InetAddress类是没有显式的构造函数的,所以只能通过它的静态函数来获取对象,InetAddress主要就有两个重要的变量,一个是IP地址,一个就是对应的域名(主机名)。因此下面的函数都是通过这两个变量来实现对象建立的,几个函数分别为:
  static InetAddress getByName(String host)
  static InetAddress[] getAllByName(String host)
  static InetAddress getByAddress(byte[] addr)
  static InetAddress getByAddress(String host,byte[] addr)
  static InetAddress getLocalHost()
  对应的意思分别是:1、通过域名获取对象(的ip)2、通过域名获取对象(所有ip)3、通过ip获取对象(的域名)4、通过域名和ip对象5、获取本机对象。第二个与第一个区别就在于它会获取多个对象,因为有些域名是有多个IP地址的。

  2、成员函数

  InetAddress类中实现了一些常用的函数:
  boolean isReachable(int timeout):地址是否可达,timeout为测试时间
  String getHostName():获取此IP地址的主机名
  byte[] getAddress():返回原始IP地址(字节数组形式)
  String getHostAddress():返回IP地址(文本形式)
  下面的部分代码测试了一些函数,可以更直观的了解这些函数的应用: 

package net;

import java.net.Inet4Address;
import java.net.InetAddress;

public class NetTest {
    public static void main(String[] args) throws Exception{
        byte[] ip = {119,75,(byte) 218,70};
        InetAddress ia = InetAddress.getByName("www.baidu.com");
        InetAddress ia2 = InetAddress.getByAddress("www.baidu.com",ip);
        InetAddress[] ia3 = InetAddress.getAllByName("www.baidu.com"); 
        System.out.println("ia ip:"+ia.getHostAddress());
        System.out.println("ia name:"+ia.getHostName());
        System.out.println("ia2 ip:"+ia2.getHostAddress());
        System.out.println("ia2 name:"+ia2.getHostName());
        System.out.println("ia3 length:"+ia3.length);
        System.out.println("ia3 byte[]:"+ia3[0].getAddress());
        System.out.println("ia3 ip1:"+ia3[0].getHostAddress());
        System.out.println("ia3 ip2: "+ia3[1].getHostAddress());
        System.out.println("local name:"+InetAddress.getLocalHost().getHostName());
        System.out.println("local ip:"+InetAddress.getLocalHost().getHostAddress());
    }
}
//输出结果
ia ip:119.75.217.109
ia name:www.baidu.com
ia2 ip:119.75.218.70
ia2 name:www.baidu.com
ia3 length:2
ia3 byte[]:[B@79b7d13e
ia3 ip1:119.75.217.109
ia3 ip2:119.75.218.70
local name:PC-201511271651
local ip:192.168.1.110

三、URLDecoder和URLEncoder

  在URL中有时候会有参杂有中文,但是当把这个URL赋值到代码编辑窗口时,中文部分显示的又不是中文,而是类似于%E5%88%98%E8%AF的一个形式,其实这里涉及到一些字符的编码转换,URLDecoder和URLEncoder两个类就是用来做转换的,其中没有定义构造函数,分别包含静态的decode()方法和encode()方法,可以直接通过类名来调用。
  String decode(String s, String enc):s用enc解码方式解码
  String encode(String s, String enc):s用enc编码方式编码
  关于其中涉及的application/x-www-form-urlencoded等可以参考:
  http://www.aikaiyuan.com/6324.html

package net;
import java.net.*;

public class NetTest {
    public static void main(String[] args) throws Exception{
        //下面是一个完整的url,其中的中文被编码了,下面取出进行解码
        String str = "http://image.baidu.com/search/index?tn="
                + "baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-"
                + "1&fr=&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab="
                + "0&fb=0&width=&height=&face=0&istype=2&ie=utf-8"
                + "&word=%E5%88%98%E8%AF%97%E8%AF%97&oq=%E5%88%98"
                + "%E8%AF%97%E8%AF%97&rsp=-1";
        String str0 = "%E5%88%98%E8%AF%97%E8%AF%97";   //中文部分
        String str1 = URLDecoder.decode(str0,"utf-8"); //解码
        String str2 = URLEncoder.encode(str1,"utf-8"); //编码
        System.out.println("str1: "+str1);
        System.out.println("str2: "+str2);
    }
}
//结果
str1: 刘诗诗
str2: %E5%88%98%E8%AF%97%E8%AF%97

四、URL、URLConnection、HttpURLConnection

  1、URL

  url即统一资源定位器,它指向网络资源的目录或文件,可以简单的视为网址,url主要有协议名,主机名,端口号,资源等组成。例如:http://img.ivsky.com/img/tupian/t/201602/16/shiweiyan-004.jpg,它的协议是http,中间是主机路径,后面为文件名,没有端口号(默认80)。
  Java中的URL类就是这样一个处理url的类,它的对象有协议,主机,端口,文件等多个变量。下面介绍它的构造函数,URL有很多个构造函数,可以通过传出相应的字段来创建,最常用的就是直接传入一个url了,下面给出两个基本的函数:
  public URL(String spec)
  public URL(String protocol, String host, String file)
  在创建了对象之后,类中提供了许多函数来获取类成员,下面的函数看名字就知道什么意思了,都是获取url对象相应的字段:
  String getQuery()
  String getPath()
  String getUserInfo()
  int getPort()
  String getProtocol()
  String getHost()
通过例子看看就行了:

public class NetTest {
    public static void main(String[] args) throws Exception{
        URL url1 = new URL("http://blog.csdn.net/anialy/article/details/8364652");
        URL url2 = new URL("http","img.ivsky.com/img/tupian/t/201602/16/","shiweiyan-004.jpg");
        System.out.println("url1.protocol: "+url1.getProtocol());
        System.out.println("url1.host: "+url1.getHost());
        System.out.println("url1.path: "+url1.getPath());
        System.out.println("url1.port: "+url1.getPort());
        System.out.println("url1.file: "+url1.getFile());
        System.out.println("url1.query: "+url1.getQuery());
        System.out.println("url1.userinfo: "+url1.getUserInfo());
        System.out.println("url1.default protocol: "+url1.getDefaultPort());

        System.out.println(url1);
        System.out.println(url2);

        //URLConnection;
        //HttpURLConnection
    }
}
//输出
url1.protocol: http
url1.host: blog.csdn.net
url1.path: /anialy/article/details/8364652
url1.port: -1
url1.file: /anialy/article/details/8364652
url1.query: null
url1.userinfo: null
url1.default protocol: 80
http://blog.csdn.net/anialy/article/details/8364652
http://img.ivsky.com/img/tupian/t/201602/16/shiweiyan-004.jpg

  类URL中还有函数URLConnection openConnection()用来建立一个连接对象。openStream来打开一个输入流读取数据 ,实际上就是URLConnection中的getInputStream(),下面都会讲。

  2、URLConnection

  URLConnection类是一个抽象类,它是所有应用程序和URL通信连接类的超类,典型的一个就是HttpURLConnection类,它就是类  URLConnection的一个子类。常用的一种用法就是:URLConnection urlConnection = url.openConnection();建立一个连接,至于urlConnection是抽象类实例的解释:这是多态性的一种用法,也叫面向接口编程,urlConnection只是一个引用。具体可以参考这里
  类URLConnection中定义了许多连接通信方面的函数,主要在其子类中得到应用,这里介绍一下常见函数:
  设置连接属性:
  setDoOutput(true);// 使用 URL 连接进行输出
  setDoInput(true);// 使用 URL 连接进行输入
  setUseCaches(false);// 忽略缓存
  setRequestMethod(“POST”);//设置URL请求方法 (属于子类HttpURLConnection)
  设置请求属性:
  setRequestProperty(String key, String value)
  key:”Content-Type”,”Connection”,”Charset”,user-agent…..
  其他:
  connect():打开一个url对应的连接
  OutputStream getOutputStream():返回连接输出流
  InputStream getInputStream():返回连接输入流

  3、HttpURLConnection

  HttpURLConnection类是URLConnection的一个子类,用于支持有关http协议的连接。下面实现一个向服务器发送GET请求并获取响应信息的例子:

package net;
import java.io.*;
import java.net.*;
import java.util.List;
import java.util.Map;

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

        String urlstr = "http://www.csdn.net/";
        //System.out.println(url.getProtocol());
        URL url = new URL(urlstr);  //建立URL对象 

        //建立一个http连接对象
        HttpURLConnection huc = (HttpURLConnection) url.openConnection(); 

        //设置请求头属性(字段可以参考浏览器,这个就是模拟浏览器向服务器发送请求)
        huc.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");   
        huc.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0");   
        huc.setRequestProperty("Connection", "Keep-Alive");// 维持长连接     

        huc.connect();         //获取连接

        //输出获取到的响应头部信息(按字段)
        Map<String, List<String>> map = huc.getHeaderFields();
        for(String key:map.keySet())
            System.out.println(key+":"+map.get(key));
    }
}
//输出
null:[HTTP/1.1 200 OK]
ETag:["571c264a-18db2"]
Vary:[Accept-Encoding, Accept-Encoding]
Date:[Sun, 24 Apr 2016 01:55:40 GMT]
Content-Length:[101810]
Last-Modified:[Sun, 24 Apr 2016 01:50:02 GMT]
Keep-Alive:[timeout=20]
Accept-Ranges:[bytes]
Connection:[keep-alive]
Content-Type:[text/html; charset=utf-8]
Server:[openresty]

  有关相关函数或参数等应用说明可以参考这里参数详解
  下面实现下载网页源代码的例子,传入一个ULR,可以获取到该网页的源代码内容:

package net;
import java.io.*;
import java.net.*;

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

        String urlstr = "http://www.csdn.net/";
        URL url = new URL(urlstr);  //建立URL对象 
        //建立一个http连接对象
        HttpURLConnection huc = (HttpURLConnection) url.openConnection(); 
        huc.connect();     //获取连接(不重要,下面一般会隐式执行)
        //从连接返回一个输入流
        InputStream is = huc.getInputStream();
        /**
         * 这里必须添加"utf-8",不然网页中文部分是乱码的,
         * InputStreamReader就是将byte类型的is按照"utf-8"方式转换成字符类型
         */
        BufferedReader buffer = new BufferedReader(new InputStreamReader(is,"utf-8"));
        StringBuffer bs = new StringBuffer();
        String str = null;
        while((str=buffer.readLine())!=null){  //读取响应信息
            bs.append(str).append("n");
          }
        System.out.println(bs);
    }
}

  上面的输出结果就是网页的源代码了,和直接在浏览器打开的源代码是一样的。可以利用这个代码分析做一些爬虫之类的都可以。

五、SocketSever、Socket

  这一节主要简答介绍有关tcp通信的内容,即socket编程,这是进行可靠通信的主要内容,用于建立客户端和服务器端的连接,因此也可以叫做客户端-服务器编程。
  
  1、Socket

  Socket类是Java中用于建立连接端口的一个类,即通过Socket实例建立一个通信接口用于与服务器通信。多用于客户端,常见两种创建方式:
  Socket(String host, int port)
  Socket(InetAddress address, int port)
都是要输入主机名和端口号,第二种的主机名是通过InetAddress类对象传递的。在Socket中还有两个重要的流处理函数:
  InputStream getInputStream()
  OutputStream getOutputStream()
两个函数额作用用于给Socket对象返回一个输入/输出流对象,用于进行连接端的信息传输。在Socket中还封装了许多相关处理的函数,这里不再详述。

  2、SeverSocket

  这个类是用于服务器创建一个监听Socket,用来监听来自客户端的请求信息。创建方式:
  ServerSocket(int port) //针对特定端口的Socket
当服务器创建了一个Socket之后,需要开始工作,即监听来自客户端的信息并响应,这里应用到的函数就是accept(),它用来监听来自客户端的连接并返回一个Socket对象来处理该连接。

  3、Server-Client
  下面代码通过创建Socket实现客户端和服务器端的连接并实现互相发送信息的功能:

//客户端

import java.io.*;
import java.net.*;

public class Client {
    public static void main(String[] args) throws IOException{
        //获取本机地址
        InetAddress ip = InetAddress.getLocalHost();
        System.out.println(ip.getHostName());
        System.out.println(ip.getHostAddress());
        //利用本机地址和端口号20000创建一个socket访问服务器
        Socket socket = new Socket(ip,20000);
        //接收服务器信息(处理流)
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = br.readLine();
        System.out.println("服务器的数据:"+line);
        //向服务器发送数据
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("你好,这里是客户端");

        ps.close();
        br.close();
    }
}
//服务器端

import java.io.*;
import java.net.*;

public class Server {
    public static void main(String[] args) throws IOException{
         //创建一个serversocket,端口号20000
        ServerSocket sever = new ServerSocket(20000);  
        while(true){
            System.out.println("waiting!");    //等待连接
            Socket socket = sever.accept();    //获取到连接返回一个socket
            //获取客户端地址
            InetAddress address = socket.getInetAddress();
            System.out.println("主机名:"+address.getHostName());
            System.out.println("ip地址:"+address.getHostAddress());
            //向客户端发送数据(应用处理流)
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println("你好,这里是服务器");
            //接收客户端数据
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = br.readLine();
            System.out.println("客户端的数据:"+line);

            br.close();   //这里会关闭socket
            ps.close();
        }
    }
}

  上面就是实现Socket通信的简单代码,客户端和服务器端相互独立。这里再介绍如何在eclipse中测试这个代码,这里建立两个工程,分别为客户端和服务器端工程,在eclipse中都为打开状态,首先点击到服务器工程所在页面,运行,这时服务器就开始监听连接了,然后打开客户端页面,运行,这时客户端就会运行并向服务器发送数据。虽然在同一台电脑上操作,但是地址等都是真实的,因此可以很好的模拟出实际的运行效果。通过控制台窗口可以看到各自的输出信息:

//服务器端
waiting!
主机名:PC-201511271651.lan
ip地址:192.168.1.110
客户端的数据:你好,这里是客户端
waiting!

//客户端
PC-201511271651
192.168.1.110
服务器的数据:你好,这里是服务器

这里分别输出了各自收到对方发送的信息,并且显示的地址和主机名也是一样的,可见数据的传输通道是建立且正确的。需要注意的是上面的代码中并没有直接关闭socket,因为在对应socket的处理流执行关闭(close)的过程中,sockct是会随之关闭的,因此在数据没有完全传输完之前不要将流关闭,不然socket也会关闭。如在上面的客户端若是在读取完服务器信息后马上关闭流br,那么流ps就不能再向服务器发送数据了,因为这时socket已经关闭,连接断开了是不能发送的。

  上面我们分别看了客户端和服务器端控制台窗口消息,在eclipse中这两个消息是显示在不同的控制台窗口的,在eclipse中可以切换窗口(或者可以这样理解:在eclipse中可以同时运行多个工程,每个工程是独立的,有各自的控制台),方式:
  这里写图片描述

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/ahafg/article/details/51225144
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-04-19 17:43:24
  • 阅读 ( 954 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢