源码分析(持续更新)

OkHttp

Android基础网络编程:socket,HttpURLConnection,HttpClient

socket

socket通信模型
在这里插入图片描述
在这里插入图片描述
socket是什么

  • 是一个对TCP/IP协议进行封装的编程调用接口(不是协议,属于传输层,是api)
  • 成对出现,一对套接字:包括ip地址和端口号

Socket与Http区别

  • Http采用Request-Response方式,Http协议属于应用层
  • Socket采用服务器主动发送数据的方式,Socket属于传输层

Socket如何实现(TCP)

//客户端
public void TCPSendMessage(String msg){
	Socket socket = null;
	OutputStream output = null;
	InputStream input = null;
	try{
		socket = new Socket("192.168.1.100",8888);
		output = socket.getOutputStream();
		output.write(msg.getBytes());
		socket.shutdownOutput();
		input = socket.getInputStream();
		byte[] b = new byte[1024];
		int len = -1;
		StringBuffer sb = new StringBuffer();
		while(len = input.read(b) != -1){
			sb.append(new String(b,0,len,Charset.forName("gbk")));
		}
		//todo 在主线程中更新UI
	}catch(UnknownHostException e){
		e.printStackTrace();
	}catch(IOException e){
		e.printStackTrace();
	}finally{
		try{
			if(socket != null){
				//输出流对象outputStream不需要关闭,因为并没有创建输出流,只是从Socket获取的
				socket.close();
			}
		}catch(IOException e){
		}
			e.printStackTrace();
	}
}

//服务器端
public void ReceiveMessage(){
	ServerSocket server = null;
	Socket socket = null;
	try{
		server = new ServerSocket(8888);
		while(true){
			socket = server.accept();
			InputStream input = socket.getInputStream();
			BufferInputStream bis = new BufferInputStream(input);
			byte[] b = new byte[1024];
			int len = -1;
			while(len = bis.read(b) != -1){
				System.out.println(new String(b,0,len,"UTF-8"));
			}
			socket.shutdownInput();
			OutputStream outputResult = socket.getOutputStream();
			outputResult.write("The message has received".getBytes());
			bis.close();
			socket.close();
			socket = null;
		}
	}catch(IOException e){
		e.printStackTrace();
	}
}

WebSocket

Http轮询

轮询是在特定的时间间隔,由浏览器(客户端)对服务器发出Http请求,然后由服务器返回最新的数据给浏览器

  • 短轮询
    缺点:在某个时间段内server没有更新数据,但client仍然每隔一段时间发送请求来询问,所以这段时间内的询问都是无效的

  • 长轮询
    收到request会查看数据是否更新,除非更新再返回response

轮询缺点:

  • 浪费带宽(Http Head比较大)
  • 消耗服务器CPU资源

Websocket与Http

  • 与Http同等的网络协议
  • 双向通信协议(服务器可以主动发送数据给客户端)

Websocket与Socket

  • Socket并不是一个网络协议
总结
  1. 本质上是一个基于TCP的协议
  2. 建立WebSocket连接需要向服务器发起一个Http请求,Head中加入"Upgrade:WebSocket"
  3. 服务器端解析这些附加的头信息
okhttp连接websocket
void sendWebSocketReq(final String hostName, final String jsonData, final WebSocketCallBack callBack) {
		//构建request
        final Request request = new Request.Builder().url(hostName).build();
        //建立websocket
        client.newWebSocket(request, new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
                super.onOpen(webSocket, response);
                //onOpen代表连接服务器成功,在此方法发送数据
                Log.i(hostName, "websocket Json: " + jsonData);
                webSocket.send(jsonData);
                Log.i(hostName, "onOpen: " + "message: " + request);
            }

            @Override
            public void onMessage(WebSocket webSocket, String text) {
                super.onMessage(webSocket, text);
                Log.i(hostName, "onMessage: " + text);
                callBack.onSuccess(webSocket, text);
                webSocket.cancel();
            }

            @Override
            public void onMessage(WebSocket webSocket, ByteString bytes) {
                super.onMessage(webSocket, bytes);
                Log.i(hostName, "onMessage: " + bytes.toString());
                callBack.onSuccess(webSocket, bytes.toString());
                webSocket.cancel();
            }

            @Override
            public void onClosing(WebSocket webSocket, int code, String reason) {
                super.onClosing(webSocket, code, reason);
                Log.i(hostName, "onClosing: " + "code: " + code + "reason:" + reason);
            }

            @Override
            public void onClosed(WebSocket webSocket, int code, String reason) {
                super.onClosed(webSocket, code, reason);
                Log.i(hostName, "onClosed: " + "code: " + code + "reason:" + reason);
                callBack.onClosed();
            }

            @Override
            public void onFailure(WebSocket webSocket, Throwable t, @Nullable Response response) {
                super.onFailure(webSocket, t, response);
                Log.i(hostName, "onFailure: " + "error: " + t.getMessage());
                callBack.onFailure(t.toString());
                webSocket.cancel();
            }
        });

        client.dispatcher().executorService();
    }

//Websocket外部回调接口,对应WebSocketListener
public interface WebSocketCallBack {

    void onSuccess(WebSocket webSocket,String response);

    void onFailure(String errorInfo);

    void onClosed();

}

Http缓存

强制缓存
  • Expires(Http1.0)
    Expires的值为服务器返回的到期时间
    存在问题:到期时间是由服务端生成的,有可能造成缓存读取的误差

  • Cache-Control
    是由服务器返回的Response中添加的头信息

  • private 客户端可以缓存

  • public 客户端和代理服务器都可以缓存

  • max-age 缓存将在若干秒后失效

  • no-cache

  • no-store

在这里插入图片描述

对比缓存

在这里插入图片描述

  • ETag:服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识
  • If-None-Match:再次请求服务器时,通过此字段通知服务器客户端缓存数据的唯一标识
  • Last-Modified:服务器在响应请求时,告诉浏览器资源的最后修改时间
  • If-Modified-Since:再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源的最后修改时间

断点续传

public void downloadWithOkHttp(){
	InputStream is = null;
	long downloadLength = 0;
	String downloadUrl = "www.morganchain.xxx.apk";
	String fileName = downloadUrl.subString(downloadUrl.lastIndexOf("/"));
	String directory = Environment.getExternalStoragePublishDirectory(Environment.DIRECTORY_DOWNLOADS);
	File file = new FIle(directory + fileName);
	if(file.exists()){
		downloadLength = file.length();
	}
	long contentLength = getContentLength(downloadUrl);
	
	OkHttpClient client = new OkHttpClient();
	Request request = new Request.Builder();
					.addHeader("RANGE","bytes=" + downloadLength + "-")//断点续传要用到,指示下载区间
					.url(downloadUrl)
					.build();
	try{
		Response response = client.newCall(request).execute();
		if(response != null){
			is = response.body().byteStream();
			RandomAccessFile saveFile = new RandomAccessFile(file,"rw");
			saveFile.seek(downloadLength);//跳过已经下载的字节
			byte[] b = new byte[1024];
			int total = 0;
			int len = 0;
			while((len = is.read(b)) != -1){
				total += len;
				saveFile.write()b, 0, len);
				//计算已经下载的百分比
				int progress = (int)((total + downloadLength) * 100 / contentLength);
			}
		}
	}catch(){
	}

}

多线程下载

  • 每个线程只负责下载文件的一部分

Https对称加密/不对称加密

在这里插入图片描述

  • Https是一种基于SSL/TLS的Http协议

  • Http所有传输的内容都是明文,Https所有传输的内容都经过加密(对称+不对称)

  • 对称加密是指加密和解密用的是同一密钥

  • 不对称加密和解密使用的密钥不是同一密钥

  • 对称加密所使用的密钥可以通过非对称加密的方式发送出去

Glide

图片三级缓存&LRUCache

  • 内存-本地-网络
    首次打开app,加载网络图片时,系统会将该图片在内存和本地各一份,当再次加载该图片时,系统先判断内存中是否有该图片,如果有则加载,没有则在本地中寻找,如果有则加载,如果内存和本地都没有该图片缓存,则去网络中加载
  • 内存缓存是如何实现的?
  • LRU(Least Recently Used)缓存算法
    缓存策略主要包括添加,获取,删除三种操作,内存满时,会删除近期最少使用的缓存
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值