Android okhttp3 创建Socket的底层实现追踪
来源:互联网 发布:阐释者淘宝 编辑:程序博客网 时间:2024/06/13 01:42
1.概述
OkHttp3的最底层是Socket,而不是URLConnection,它通过Platform的Class.forName()反射获得当前Runtime使用的socket库,调用栈如下
okhttp//实现HTTP协议
==>framwork//JRE,实现JDK中Socket封装
==>jvm//JDK的实现,本质对libc标准库的native封装
==>bionic//android下的libc标准库
==>systemcall//用户态切换入内核
==>kernel//实现下协议栈(L4,L3)与网络驱动(一般是L2,L1)
注:需求决定,Android版本4.4.4 okhttp 3.2.0
2.因为底层使用Socket,所以在okhttp3源码全局搜索"new Socket"这个关键词,定位在:
okhttp3.internal.io.RealConnection#connect
rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP ? address.socketFactory().createSocket() : new Socket(proxy);
3.在此处打断点,调试
rawSocket为
所以address.socketFactory()返回的是DefaultSocketFactory.java
4./libcore/luni/src/main/java/javax/net/DefaultSocketFactory.java
/** * Default implementation of {@link javax.net.SocketFactory} */final class DefaultSocketFactory extends SocketFactory { DefaultSocketFactory() { } @Override public Socket createSocket() throws IOException { return new Socket(); }
public Socket() { this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl(); this.proxy = null; }
6./libcore/luni/src/main/java/java/net/PlainSocketImpl.java
public PlainSocketImpl() { this(new FileDescriptor()); }
7.以上步骤还没通过jni调用libc.so,真正创建socket是在connectSocket中
okhttp3.internal.io.RealConnection#connect
connectSocket(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);
/** Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */ private void connectSocket(int connectTimeout, int readTimeout, int writeTimeout, ConnectionSpecSelector connectionSpecSelector) throws IOException { rawSocket.setSoTimeout(readTimeout);
/** * Sets this socket's {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds. * Use 0 for no timeout. * To take effect, this option must be set before the blocking method was called. */ public synchronized void setSoTimeout(int timeout) throws SocketException { checkOpenAndCreate(true); if (timeout < 0) { throw new IllegalArgumentException("timeout < 0"); } impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); }
10./libcore/luni/src/main/java/java/net/Socket.java#checkOpenAndCreate
/** * Checks whether the socket is closed, and throws an exception. Otherwise * creates the underlying SocketImpl. * * @throws SocketException * if the socket is closed. */ private void checkOpenAndCreate(boolean create) throws SocketException { if (isClosed()) { throw new SocketException("Socket is closed"); } if (!create) { if (!isConnected()) { throw new SocketException("Socket is not connected"); // a connected socket must be created } /* * return directly to fix a possible bug, if !create, should return * here */ return; } if (isCreated) { return; } synchronized (this) { if (isCreated) { return; } try { impl.create(true); } catch (SocketException e) { throw e; } catch (IOException e) { throw new SocketException(e.toString()); } isCreated = true; } }
最后调用PlainSocketImpl.java的create
10./libcore/luni/src/main/java/java/net/PlainSocketImpl.java
protected void create(boolean streaming) throws IOException { this.streaming = streaming; this.fd = IoBridge.socket(streaming); }
11./libcore/luni/src/main/java/libcore/io/IoBridge.java
public static FileDescriptor socket(boolean stream) throws SocketException { FileDescriptor fd; try { fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0); // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults // to 1. The Linux kernel (at least up to 2.6.38) accidentally defaults to 64 (which // would be correct for the *unicast* hop limit). // See http://www.spinics.net/lists/netdev/msg129022.html, though no patch appears to // have been applied as a result of that discussion. If that bug is ever fixed, we can // remove this code. Until then, we manually set the hop limit on IPv6 datagram sockets. // (IPv4 is already correct.) if (!stream) { Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1); } return fd; } catch (ErrnoException errnoException) { throw errnoException.rethrowAsSocketException(); } }总算往jni方向去了:Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0)
可见:创建socket时,domain为AF_INET6,类型为SOCK_STREAM(对于http来说)
在c层可以用这两个条件来过滤http的socket创建
12.
/libcore/luni/src/main/java/libcore/io/BlockGuardOs.java
public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { return tagSocket(os.socket(domain, type, protocol)); }
/libcore/luni/src/main/java/libcore/io/ForwardingOs.java
public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { return os.socket(domain, type, protocol); }
public native FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;
static jobject Posix_socket(JNIEnv* env, jobject, jint domain, jint type, jint protocol) { int fd = throwIfMinusOne(env, "socket", TEMP_FAILURE_RETRY(socket(domain, type, protocol))); return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;}
NATIVE_METHOD(Posix, socket, "(III)Ljava/io/FileDescriptor;"),
15./bionic/libc/arch-arm/syscalls/socket.S
socket通过汇编实现,汇编代码中通过swi调用中断号实现功能
ENTRY(socket) mov ip, r7 ldr r7, =__NR_socket swi #0 mov r7, ip cmn r0, #(MAX_ERRNO + 1) bxls lr neg r0, r0 b __set_errnoEND(socket)
至此,socket创建跟踪完毕~
- Android okhttp3 创建Socket的底层实现追踪
- Android okhttp3 进行socket connect&poll的底层实现跟踪
- Android okhttp3 DNS 底层实现追踪(一)
- Android okhttp3 DNS 底层实现追踪(二)
- Android okhttp3 利用socket进行read/write的底层实现跟踪
- socket的底层创建与关闭
- socket的底层创建与关闭 (A)
- 关于Socket的底层实现功能
- 内核中的TCP的追踪分析-2-追踪TCP(IPV4)的socket的创建
- Socket底层实现
- Socket底层实现
- android okhttp3的封装
- 创建自己的Queue底层实现是链表
- 4-socket的实践到内核--追踪socket的创建
- 4-socket的实践到内核--追踪socket的创建 .
- 使用OKHttp3替换Volley的底层网络请求
- JAVA Socket 底层是怎样基于TCP/IP实现的???
- JAVA Socket 底层是怎样基于TCP/IP 实现的
- GridView基于pulltorefresh实现下拉刷新 上拉加载更多功能
- 如何将服务器上oracle11g数据dump出来导入到本地的oracle10版本
- 统计APK中方法数量
- apple mach-o linker error 报错解决
- 【PAT甲级】1067. Sort with Swap(0,*) (25)
- Android okhttp3 创建Socket的底层实现追踪
- Monocular slam 理论基础(2)
- iOS -- UITableView基本使用
- NFS服务基本配置及使用
- objc_setAssociatedObject 使用
- 算法的可视化工具
- 数据库常见时间函数的用法
- oj-9-G-计算平均分
- VMware虚拟机安装win10的方法