热度 12
2015-12-3 20:48
2683 次阅读|
0 个评论
必须在子线程中执行网络操作,不然会抛出异常 我已验证: url.openConnection()不会进行物理网络连接: netstat看不到有连接! HttpURLConnection.connect()会进行物理网络连接: netstat能看到有连接ESTABLISHED(如果没有进行disconnect())。如果disconnect(),那就来不及看了。 (1)不写connect(),直接用getInputStream()是可以的,它发现没有连接的话,会默认先进行connect() (2)先connect(),再getResponseMessage(),再getInputStream(),是可以的 (3)看源文件,getResponseCode() 里会先getInputStream(),说明会默认先进行连接,再得到responsecode。 因为responsecode其实也是网站发来的数据中的一部分。 URL中的端口可以这样: URL url=new URL("http://192.168.0.63:8888"); ,这样是连接8888端口 HttpURLConnection connection =(HttpURLConnection) url.openConnection(); ,不会进行网络连接,只是生成URLConnection对象 ↓ 对HttpURLConnection对象(http头)进行配置(一堆set函数) ↓ 对outputStream流(请求正文)写入(写入的东西不会发送到网络,而是存在于缓冲区中) ↓ connect():会根据配置值生成http头部信息,并进行TCP网络连接 ↓ getInputStream():把请求(http头+请求正文)正式发送出去,并得到输入流(网站发来的数据)。它得到的是数据正文。数据头信息可以用getResponseCode()等来得到。 引用网友说的: a:) HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。 无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。 b:) 在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重,对connection对象的一切配置(那一堆set函数) 都必须要在connect()函数执行之前完成。 而对outputStream的写操作,又必须要在inputStream的读操作之前。 这些顺序实际上是由http请求的格式决定的。 如果inputStream读操作在outputStream的写操作之前,会抛出例外: java.net.ProtocolException: Cannot write output after reading input....... c:) http请求实际上由两部分组成,一个是http头,所有关于此次http请求的配置都在http头里面定义,一个是正文content。 connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前,就必须把所有的配置准备好。 d:) 在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的,实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。 至此,http请求的东西已经全部准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。 由于http请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。 connect()方法:打开到此URL引用的资源的通信链接(如果尚未建立这样的连接)。如果在已打开连接(此时connected字段的值为true)的情况下调用connect方法,则忽略该调用。 URLConnection对象经历两个阶段:首先创建对象,然后建立连接。在创建对象之后,建立连接之前,可指定各种选项(例如,doInput和UseCaches)。连接后再进行设置就会发生错误。连接后才能进行的操作(例如getContentLength()),将隐式地先执行连接。 所以,有的方法会隐式地执行connect()方法。conn.openInputStream();//隐式执行了connect方法。此方法的实现sun.net.www.protocol.http.HttpURLConnection.getInputStream好像没有开源。 It should be noted that a URLConnection instance does not establish the actual network connection on creation. This will happen only when calling {@linkplain java.net.URLConnection#connect() URLConnection .connect() }. openConnection只是创建了,还没有正式的连接到远程。调用connect,才开始打开连接,发出请求! url.openconnection();方法原形:public URLConnection openConnection()。返回一个 URLConnection 对象。如果 URL 的协议(例如,HTTP 或 JAR)存在属于以下包或其子包之一的公共、专用 URLConnection 子类:java.lang、java.io、java.util、java.net,返回的连接将为该子类的类型。例如,对于 HTTP,将返回 HttpURLConnection,对于 JAR,将返回 JarURLConnection。 可以看出:url对象用openconnection()获得URLConnection类对象,再用URLConnection类对象的connect()方法进行连接。 测试: import java.net.URL; import java.net.HttpURLConnection; import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; new Thread(new Runnable() { @Override public void run() { String str=""; String g_str=""; HttpURLConnection connection=null; try { URL url=new URL("http://192.168.0.63:8888"); connection =(HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); //如果超时,则会抛出异常 connection.setReadTimeout(8000); InputStream in=connection.getInputStream(); BufferedReader reader=new BufferedReader(new InputStreamReader(in)); StringBuilder sb=new StringBuilder(); while((str=reader.readLine())!=null) sb.append(str); g_str+=sb.toString(); } catch(Exception e) { //e.printStackTrace(); g_str=e.toString(); } finally { if(connection!=null) connection.disconnect(); } } //这里可以对g_str进行处理了 }).start();