java建立Internet连接的一般流程

1、首先,我们需要新建一个HttpURLConnection,

  这个类是继承自URLConnection的一个抽象类,不争,我们要做的任何一件事,首先都是要新建一个实例,new 一个object

2、既然眼前有了这样的一台机器,就要考虑给他加参数,然后开启开关,访问网站,

  于是,就需要新建一个输入流,对吧,任何输入流都是向服务器传送字节流的时候用的到的(这个时候,我们本地的java代码就是运行在本地电脑,也可以理解为本地服务器),同样的,输出流都是用在文件下载用的,为啥,因为需要将字节流输出到本地或者从服务器远程给到客户端

3、同时,需要对传入本地的输入流按照字符的形式传入吧?那些个网页上的html代码都是UTF-8或者GBK编码的字符,传进来当然是要按照字符流来传入的吧?那么不争,你要再新建一个BufferedReader咯!

4、既然准备就绪了,那么我们就可以开始对网站进行访问了,但是网站是啥呢?当然要传入网站名:URL url="https://www.cnblogs.com/cyh2009",这里我们以博客园为例,你要问为啥不是String,因为URL内置了openConnection

5、网站好了,于是我们就可以打开连接,connection = (HTTPURLConnection)url.openConnection();这里有个让我们不舒服的地方,打开么就打开了,非要加个(HttpURLConnection)来强制,为啥?

因为,url字符串,是String吧?String有openConnection吗?当然没有,String有的,只是我们常见的toString()(参见String.class类),只有URL类里面,才有openConnection

哦对,URL是一个类,你猜谁写的?没错,是大神写的

 

 

 

 

再者,奇葩的地方在于,URL内部的openConnection返回类型,是URLConnection,不要忘了,这个是HttpURLConnection的父类,是一个抽象类,而非我们眼前所需要用的HttpURLConnection,既然源码没有改变,没有按照我们心里想的样子写的,那就只有在返回类型前面加上一个强制转换了

6、open完了之后,我们想起来,web连接是不是需要设置方式,那我们就以get为例?因为我们访问的是链接

7、既然方式设置好了,连接也有了,然后就可以进行连接了,connection.connect()

8、打开connect()方法一看,这个方法有点奇葩,是一个抽象的声明方法:

abstract public void connect() throws IOException;

一脸懵逼了吧?就这申明方法能运行?不要忘了,我们的HttpURLConnection是继承自哪里的?URLConnection,所以我们就去URLConnection找找

未完待续...

 

 

 

 

 看到没,有意思不,实现方法之多,就仅仅这一个connect抽象方法的实现,就不胜数,然后你以为能点开看到源码了?

这样想下去,就是钻牛角尖了...

 

所谓http访问,都存在一个过程,HTTP访问,都要建立TCP连接吧?你们看不到的建立,就在connect()中,当然只有建立完了,才可以获取数据呀,对吧?

既然建立了连接,必然有响应码吧?这样的话,必然是经过三次握手,建立连接完了以后,才有的响应码,比如,连接成功,相应200,完了之后,才开始接收数据?

什么,你说为啥不是同时接收响应码和数据呢?

所谓同时,这样的概念,是我们用浏览器访问网站的时候,界面给我们形成这样的理解,你在调试模式中,会发现,响应码和数据都是一起过来的吧?

比如你输入一个“www.baidu.com”,他实际上是浏览器访问网站后,接收到响应码200后,又接收到网站返回的html文件信息(当然这html文件信息,动态还是静态也不好说,要看对方服务器的意思)

 

 

但是我们java连接的时序,他就是这样的,他将所有这些连接的步骤,拆分成各个功能模块,拆分成各个类,负责各个方法,来控制各个步骤,当然,这些连接所涉及到底层计算机http连接的硬件工作,就依赖我们的java虚拟机编译了,这个你想看吗?我也想看,但是这个是sun的核心,

大家要明白一个特点,所谓的开源,什么是开源?在我们工作中完成一项功能所涉及到的代码组合,以一种清晰的,透明的方式展现给我们的编码人员,并且,在使用上,根据开源协议,可以拿来使用,这样的代码,是称作为开源

 

 

假如,你的面前有一台机器,这台机器有着四种操作指令,分别为1、往前走 2、左转 3、右转 4、后退,于是你在这样的基础上,设计了一套“机器驾驶系统”,这套系统有“1234”四种指令组成,共200行代码指令,那这两百行代码指令,你可以拿来开源

但是,并不是意味着,别人知道指令一,往前走,就明白这个指令和这台机器的电路信号之间到底有着什么样的关系?比如,有个人想修改指令一,修改为往前走再转头,他可以修改吗?作为开发者的你,并没有将指令和机器电信号之间的关系,以及设计原理开源,别人就无法修改,除非破解,这个题外话

 

java虚拟机是一个给人提供解释语言,来运行的一台机器,他有他的编译原理,但是,这个 编译原理,并没有向公众揭秘,一个HttpURLConnection中connect方法的连接工作,以及和电信号之间的运行关系,并不能清晰的将底层展现给开发者,所以只能从他给定的方法和代码来研究常用功能的实现,是如何按照他现有的功能方法,功能类,来组合实现的这样一种功能。

而且,java虚拟机在不同的操作系统上,有不同版本的虚拟机,那虚拟机中的java原理,是一样的,比如,java是如何利用HttpURLConnection中的connect方法,来连接http,这样的控制机理是一毛一样的,但是不同的操作系统,连接控制电信号的变化方式,是不同的,而且如果操作系统开源,则能够让人一睹,就像linux,如果windows,当然就不行了,

-----------------------------------------------------------------------------------------------------------------------------------

 

回到正题,既然我们已经获取了响应码,我们就可以获取输入流了,相对于服务器输出流,我们本地输入流,是为了需要将获取到的字符,以输入流的方式,传入到我们本地的输入流实例里面,你想,我们获取本地文件,也是需要按照本地路径,将文件读入至我们的本地文件输入流里面,那么我们从http连接获取的字符流,也当然是以输入流的方式接收,对吧?

开始接收了,

我们需要用到BufferReader,这是干嘛的?按照官方API的解释如下:

  BufferedReader类从字符输入流中读取文本并缓冲字符,以便有效地读取字符,数组和行

  可以通过构造函数指定缓冲区大小也可以使用默认大小。对于大多数用途,默认值足够大

  由Reader构成的每个读取请求都会导致相应的读取请求由基础字符或字节流构成,建议通过BufferedReader包装Reader的实例类以提高效率如

这个就是java原理了,所谓的java原理,就是告诉你应该采用哪种功能类,来实例和采用哪种功能方法,所以,java就是一种给你设计的功能组件,让你像搭积木一样,来组合所需要的功能?什么,你说我骂你是傻逼,我可没这么说

 

BufferReader br = new BufferReader(new InputStreamReader(is,"UTF-8"));

牛逼不,其实是人家设计好了的,给你个代码来实现,你就觉的不可思议了是吧?

这样,就将输入流按照UTF-8的编码方式来接收,为啥呢,因为你打开BufferReader一看,里面居然有个方法叫,readLine,牛逼不?你把他写上去,他就能按照行,来返回字符串了,

其实就是将这BufferReader读取到的字符串缓存,按照行来切割成字符串,可以不断的遍历来获取。like this:

StringBuffer sbf = new StringBuffer();

BufferReader br = new BufferReader(new InputStreamReader(is,"UTF-8"));

while(null!=br.readLine()){

  sbf.append("br.readLine()");

  sbf.append(" \r\n");

}

牛逼不?其实就是抄代码,抄人家老外写的代码,写的Demo,再换一种“java原理”的称呼,来告诉大家这样的实现方式,呵呵不?

 

 

然后,你可以输出到控制台,观察。或者输出完,自己每一行都手抄下来,如果你想练练字的话,当然那样做,我会很佩服你

 

posted @ 2020-04-10 09:02  菊次郎的幻想  阅读(596)  评论(0编辑  收藏  举报

begin