java 网络编程

    和网络编程有关的基本API位于java.net包中,该包中包含了基本的网络编程实现,该包是网络编程的基础。该包中既包含基础的网络编程类,也包含封装后的专门处理WEB相关的处理类。在本章中,将只介绍基础的网络编程类。

         首先来介绍一个基础的网络类——InetAddress类。该类的功能是代表一个IP地址,并且将IP地址和域名相关的操作方法包含在该类的内部。

         关于该类的使用,下面通过一个基础的代码示例演示该类的使用,代码如下:

import java.net.*;
/**
 * 演示InetAddress类的基本使用
 */
public class InetAddressDemo {
         public static void main(String[] args) {
                   try{
                            //使用域名创建对象
                            InetAddress inet1 = InetAddress.getByName("www.163.com");
                            System.out.println(inet1);
                            //使用IP创建对象
                            InetAddress inet2 = InetAddress.getByName("127.0.0.1");
                            System.out.println(inet2);
                            //获得本机地址对象
                            InetAddress inet3 = InetAddress.getLocalHost();
                            System.out.println(inet3);
                            //获得对象中存储的域名
                            String host = inet3.getHostName();
                            System.out.println("域名:" + host);
                            //获得对象中存储的IP
                            String ip = inet3.getHostAddress();
                            System.out.println("IP:" + ip);
                   }catch(Exception e){}
         }
}

运行结果:

www.163.com/60.174.243.159
/127.0.0.1
ifly-XXX/10.1.xxx.xxx
域名:ifly-XXX
IP:10.1.xxx.xxx


Socket编程

Java为TCP协议提供了两个类,分别在客户端编程和服务器端编程中使用它们。在应用程序开始通信之前,需要先创建一个连接,由客户端程序发起;而服务器端的程序需要一直监听着主机的特定端口号,等待客户端的连接。在客户端中我们只需要使用Socket实例,而服务端要同时处理ServerSocket实例和Socket实例;二者并且都使用OutputStreamInpuStream来发送和接收数据。

服务器端:

                 ① 创建ServerSocket对象,绑定监听端口
                 ② 通过accept()方法监听客户端请求          //没有客户端请求时,accept()会阻塞,不会继续往下运行
                 ③ 连接建立后,通过输入流读取客户端发送的请求信息
                 ④ 通过输出流向客户端发送乡音信息
                 ⑤ 关闭相关资源
客户端:
                 ① 创建Socket对象,指明需要连接的服务器的地址和端口号
                 ② 连接建立后,通过输出流想服务器端发送请求信息
                 ③ 通过输入流获取服务器响应的信息
                 ④ 关闭响应资源
   注:客户端不需要设定哪个端口和服务器端进行通信,但是服务器端需要设定监听的端口号。

   学习一种知识最好的方式就是使用它,通过前面的笔记,我们已经知道如何获取主机的地址信息,现在我们通过一个简单的程序来初步学习传输层使用了TCP协议的Socket编程。

1.TCP服务器端

  在Socket编程中,服务器端远比客户端要复杂得多。服务器端的工作就是建立一个通信终端,被动的等待客户端的连接。下面这个服务器端程序的示例的作用是:监听从控制台输入获取的端口号,并且将客户端发送过来的消息,再发送回去。

import java.net.*;
import java.text.MessageFormat;
import java.io.*;

public class TCPEchoServer {

    private static final int BUFSIZE = 32;

    /**
     * @param args
   */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
     // 从控制台获取需要监听的端口号
        if (args.length != 1)
            throw new IllegalArgumentException("Parameter(s):<Port>");
        // 获取端口号
        int servPort = Integer.parseInt(args[0]);
        // 实例化一个ServerSocket对象实例
        ServerSocket servSocket = new ServerSocket(servPort);
        System.out.println(MessageFormat.format("开始启动监听,端口号:{0}", args[0]));

        // 初始接收数据的总字节数
        int recvMsgSize;
        // 接收数据的缓冲区
        byte[] receiveBuf = new byte[BUFSIZE];

        // 循环迭代,监听端口号,处理新的连接请求
        while (true) {
            // 阻塞等待,每接收到一个请求就创建一个新的连接实例
            Socket clntSocket = servSocket.accept();
            // 获取连接的客户端的 SocketAddress
            SocketAddress clientAddress = clntSocket.getRemoteSocketAddress();
            // 打印输出连接客户端地址信息
            System.out.println("Handling client at" + clientAddress);
            // 从客户端接收数据的对象
            InputStream in = clntSocket.getInputStream();
            // 向客户端发送数据的对象
            OutputStream out = clntSocket.getOutputStream();
            // 读取客户端发送的数据后,再发送到客户端
            while ((recvMsgSize = in.read(receiveBuf)) != -1) {
                out.write(receiveBuf, 0, recvMsgSize);
            }
            // 客户端关闭连接时,关闭连接
            System.out.println(" 客户端关闭连接");
            clntSocket.close();
        }
    }
}
      while ((recvMsgSize = in.read(receiveBuf)) != -1) {
                out.write(receiveBuf, 0, recvMsgSize);
            }

上述代码中,服务端可以多次接受  客户端的消息,并将消息回传给客户端,直到客户端关闭socket时,循环才结束。

2.TCP客户端

  在Socket编程中,首先客户端需要向服务器端发送,然后被动的等待服务器端的响应。下面的示例中:我们向服务器端发送信息,等待服务器端发送的消息,并打印显示出来。 

import java.io.*;
import java.net.Socket;
import java.net.SocketException;

public class TCPEchoClient {

    /**
     * @param args
     * @throws IOException
    */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        // 判断从控制台接受的参数是否正确
        if ((args.length < 2) || (args.length > 3))
            throw new IllegalArgumentException("Parameter(s):<Server><Word>[<Port>]]");
        // 获取服务器地址
        String server = args[0];
        // 获取需要发送的信息
        byte[] data = args[1].getBytes();
        // 如果有三个从参数那么就获取发送信息的端口号,默认端口号为8099
        int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 8099;
        // 根据服务器地址和端口号实例化一个Socket实例
        Socket socket = new Socket(server, servPort);
        System.out.println("Connected to server...sending echo string");
        // 返回此套接字的输入流,即从服务器接受的数据对象
        InputStream in = socket.getInputStream();
        // 返回此套接字的输出流,即向服务器发送的数据对象
        OutputStream out = socket.getOutputStream();
        // 向服务器发送从控制台接收的数据
        out.write(data);
        // 接收数据的计数器,将写入数据的初始偏移量
        int totalBytesRcvd = 0;
        // 初始化接收数据的总字节数
        int bytesRcvd;
        while (totalBytesRcvd < data.length) {
            // 服务器关闭连接,则返回 -1,read方法返回接收数据的总字节数
            if ((bytesRcvd = in.read(data, totalBytesRcvd, data.length
                    - totalBytesRcvd)) == -1)
                throw new SocketException("与服务器的连接已关闭");
            else 
                 System.out.println("client received data from client");
            totalBytesRcvd += bytesRcvd;          
        }
        // 打印服务器发送来的数据
        System.out.println("Received:" + new String(data));
        // 关闭连接
        socket.close();

    }
}

运行服务端程序: 对8099端口进行监听:

运行客户端程序: 向服务器端发送消息(默认端口号为8099),同时服务器发回消息

服务器端变成:监听到 ip地址为 10.1.206.238:59918 的socket发送消息。

 HTTP协议

  HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程。客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一定的通讯格式,HTTP协议用于定义客户端与web服务器通迅的格式。

   http协议主要有两个版本,他们的区别:

  在HTTP1.0协议中,客户端与web服务器建立连接后,只能获得一个web资源。
  在HTTP1.1协议,允许客户端与web服务器建立连接后,在一个连接上获取多个web资源。

HTTP请求

客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求

一个完整的HTTP请求包括如下内容:一个请求行、若干消息头、以及实体内容

请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Method Request-URI HTTP-Version CRLF 
其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)。

请求方法(所有方法全为大写)有多种,各个方法的解释如下:
  GET     请求获取Request-URI所标识的资源
  POST    在Request-URI所标识的资源后附加新的数据
  HEAD    请求获取由Request-URI所标识的资源的响应消息报头
  PUT     请求服务器存储一个资源,并用Request-URI作为其标识
  DELETE  请求服务器删除Request-URI所标识的资源
  TRACE   请求服务器回送收到的请求信息,主要用于测试或诊断
  CONNECT 保留将来使用
  OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求


HTTP请求的细节——消息头

  HTTP请求中的常用消息头

  accept:浏览器通过这个头告诉服务器,它所支持的数据类型
  Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集
  Accept-Encoding:浏览器通过这个头告诉服务器,支持的压缩格式
  Accept-Language:浏览器通过这个头告诉服务器,它的语言环境
  Host:浏览器通过这个头告诉服务器,想访问哪台主机
  If-Modified-Since: 浏览器通过这个头告诉服务器,缓存数据的时间
  Referer:浏览器通过这个头告诉服务器,客户机是哪个页面来的  防盗链
  Connection:浏览器通过这个头告诉服务器,请求完后是断开链接还是何持链接


Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, 
    application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://localhost:8080/JavaWebDemoProject/Web/2.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3)
Accept-Encoding: gzip, deflate
Host: localhost:8080
Connection: Keep-Alive

HTTP响应

一个HTTP响应代表服务器向客户端回送的数据,它包括: 一个状态行、若干消息头、以及实体内容


 


HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 105
Date: Tue, 27 May 2014 16:23:28 GMT

<html>
    <head>
        <title>Hello World JSP</title>
    </head>
    <body>
        Hello World!

    </body>
</html>

HTTP响应的细节——状态行

    状态行格式: HTTP版本号 状态码 原因叙述<CRLF>
      举例:HTTP/1.1 200 OK
  状态码用于表示服务器对请求的处理结果,它是一个三位的十进制数。响应状态码分为5类,如下所示:
  

HTTP响应细节——常用响应头

  HTTP响应中的常用响应头(消息头)
  Location: 服务器通过这个头,来告诉浏览器跳到哪里
  Server:服务器通过这个头,告诉浏览器服务器的型号
  Content-Encoding:服务器通过这个头,告诉浏览器,数据的压缩格式
  Content-Length: 服务器通过这个头,告诉浏览器回送数据的长度
  Content-Language: 服务器通过这个头,告诉浏览器语言环境
  Content-Type:服务器通过这个头,告诉浏览器回送数据的类型
  Refresh:服务器通过这个头,告诉浏览器定时刷新
  Content-Disposition: 服务器通过这个头,告诉浏览器以下载方式打数据
  Transfer-Encoding:服务器通过这个头,告诉浏览器数据是以分块方式回送的
  Expires: -1  控制浏览器不要缓存
  Cache-Control: no-cache 
  Pragma: no-cache

Http协议工程运用

缓存机制

http请求自带缓存机制,当缓存中存在请求的数据时不再请求(即使没有网络返回码也是200)或者不做数据传输处理具体如下:

  从缓存取
获取资源形式 状态码 发送请求到服务器
强缓存 200(from cache) 否,直接从缓存取
协商缓存 从缓存取 304(not modified) 是,正如其名,通过服务器来告知缓存是否可用

缓存机制:https://www.cnblogs.com/wonyun/p/5524617.html

okhttp拦截器

https://blog.csdn.net/zw791029369/article/details/80723377

Http通信在Android中的使用

  初始化 定义HttpURLConnection , 通过BufferReader 按行读取传输的数据 ,最后将数据赋值给一个StringBuilder

    HttpURLConnection connection = (HttpURLConnection)url.openConnection();

  InputStream in = connection.getInputStream();

    BufferedReader reader =  new BufferedReader(new InputStreamReader(in));

package com.iflytek.internetcommunicate;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private TextView text;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

// button : push send an request for get infomation of www.baidu.com
        Button sendRequest = (Button) findViewById(R.id.ConnectInternet);
// text : dis the info in text
         text = (TextView)findViewById(R.id.DisInfo);
        sendRequest.setOnClickListener(this);
    }

    public void onClick(View v){
        if(v.getId()==R.id.ConnectInternet){
           sendRequestWithHttp();
        }
    }

    private void sendRequestWithHttp(){
        //开启线程发起网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                BufferedReader reader=null;
                try{
                    URL url =new URL("http://www.baidu.com");
                    // connection的初始化,并且调用openConnection()方法,打开连接
                    connection =(HttpURLConnection)url.openConnection();
                    connection.setRequestMethod("get");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    // inputstream 接受connect传输的数据
                    InputStream in = connection.getInputStream();

                    //通过reader读取inputstream中的数据
                    reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while((line= reader.readLine())!=null){
                        response.append(line);
                    }
                    showResponse(response.toString());
                }catch(Exception e){
                    e.printStackTrace();
                }finally {
                    if(reader!=null){
                        try {
                            reader.close();
                        }catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                    if(connection!=null){
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
    private void showResponse(final  String response){
        //android 不允许子线程 修改UI操作,必须切换到主线程才能对 UI进行修改
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                text.setText(response);
            }
        });
    }
}
HttpURLConnection


参考:

http://www.cnblogs.com/IPrograming/archive/2012/03/17/Java_Socket_3.htm

posted @ 2017-05-10 16:31  NeilZhang  阅读(258)  评论(0编辑  收藏  举报