pos機98交易超時,okhttp Timeout 超時設置與用法解釋

 新聞資訊2  |   2023-05-25 10:18  |  投稿人:pos機之家

網上有很多關于pos機98交易超時,okhttp Timeout 超時設置與用法解釋的知識,也有很多人為大家解答關于pos機98交易超時的問題,今天pos機之家(www.tjfsxbj.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!

本文目錄一覽:

1、pos機98交易超時

pos機98交易超時

1. 用法: 設置超時時間

OkHttpClient httpClient = new OkHttpClient.Builder() .retryOnConnectionFailure(true) .connectTimeout(connect_TIMEOUT, TimeUnit.SECONDS) //連接超時 .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS) //讀取超時 .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS) //寫超時 .addInterceptor(getHeaderInterceptor()) .addInterceptor(new CacheInterceptor()) .addInterceptor(new HttpLoggerInterceptor() .setLevel(BuildConfig.DEBUG ? Level.BODY : Level.NONE) .setTag(HTTP_LOG_TAG)) .build();

這個都知道, 一搜一大把, 但是沒人講這三種timeout有什么區(qū)別...

2. 總結

源碼分析之前先上總結

connectTimeout 最終設置給了socket (確切的說應該是rawSocket)readTimeout 最終設置給了rawSocket 以及 在socket基礎上創(chuàng)建的BufferedSourcewriteTimeout 最終設置給了在socket基礎上創(chuàng)建的BufferedSink

一言以蔽之: okhttp底層基于socket, 所以 Timeout 自然也是設置給?Socket 的 connect / read / write

當然, 不懂socket怎么用的最好先查一下~

以下的源碼探究就是羅列記錄以下自己的探究過程, 可以忽略~

3. 源碼探究

3.1 設置給rawSocket 上的 connectTimeout 和 readTimeout

具體實現(xiàn)在 RealConnection這個類的connectSocket(,,,)方法

/** * Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */ private void connectSocket(int connectTimeout, int readTimeout, Call call, EventListener eventListener) throws IOException { Proxy proxy = route.proxy(); address address = route.address(); //在未設置proxy的情況下, 會采用默認的proxySelector, 此時的proxy.type == DIRECT 即直連 rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP ? address.socketFactory().createSocket() // 走這里, 實際new Socket() : new Socket(proxy); eventListener.connectStart(call, route.socketAddress(), proxy); //最終調用socket.setSoTimeout方法, 設置讀取server端數(shù)據(jù)的超時; rawSocket.setSoTimeout(readTimeout); try { //實際調用的是 rawSocket.connect(route.socketAddress(), connectTimeout), 設置連接server的超時時長 Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout); } catch (ConnectException e) { ... throw ce; } // The following try/catch block is a pseudo hacky way to get around a crash on Android 7.0 // More details: // https://github.com/square/okhttp/issues/3245 // https://android-review.googlesource.com/#/c/271775/ try { //創(chuàng)建source source = Okio.buffer(Okio.source(rawSocket)); //創(chuàng)建sink sink = Okio.buffer(Okio.sink(rawSocket)); } catch (NullPointerException npe) { if (NPE_THROW_WITH_NULL.equals(npe.getMessage())) { throw new IOException(npe); } } }

關于socket.setSoTimeout, 以下是原文檔說明的個人翻譯及理解

調用此方法設置一個非0的timeout,那么調用InputStream(與此Socket相關聯(lián)的) 的read()這個阻塞方法讀取server端的數(shù)據(jù)時, 持續(xù)timeout之久。

如果timeout 到期,不管Socket是否有效, 都會拋出java.net.SocketTimeoutException。

這個timeout 必須在socket進入block操作之前設置 才能生效;

正常設置timeout >0, 如果設置timeout=0, 則代表 timeout無限;

關于socket.connect(address, connectTimeout);

Connects this socket to the server with a specified timeout value. A timeout of zero is interpreted as an infinite timeout. The connection will then block until established or an error occurs.

簡言之就是 與server建立連接的最大時長

3.2 BufferedSource上的 readTimeout 和 BufferedSink上的writeTimeout

具體實現(xiàn)在RealConnection的newCodec方法

public HttpCodec newCodec(OkHttpClient client, Interceptor.Chain chain, StreamAllocation streamAllocation) throws SocketException { if (http2Connection != null) { return new Http2Codec(client, chain, streamAllocation, http2Connection); } else { //此處又給socket設置了一次readTimeout, 當然此socket已經不一定是rawSocket了 socket.setSoTimeout(chain.readTimeoutMillis()); // source.timeout().timeout(chain.readTimeoutMillis(), MILLISECONDS); // sink.timeout().timeout(chain.writeTimeoutMillis(), MILLISECONDS); return new Http1Codec(client, streamAllocation, source, sink); } }

當然還有一個地方是在connectTunnel()用到, 但是這個前提是走http代理的時候, 這個暫且不詳細探究;

3.3 下面是source和sink中的timeout 的詳細解釋

Source 和 Sink 是 okio 中定義的兩個接口, 這兩個接口都支持讀寫超時設置

其中source可以理解為inputstream, sink可以理解為outputstream

image.png

具體是什么鬼, 看一下source和sink的創(chuàng)建就是知道了

BufferedSource的創(chuàng)建

羅列細節(jié)之前先總結一下流程:

Socket ----> InputStream ---> Source ---> BufferedSource

還是RealConnection的connectSocket方法

//創(chuàng)建BufferedSourcesource = Okio.buffer(Okio.source(rawSocket));

Okio.buffer(Source source)就是new RealBufferedSource(source);

那么下面主要來看Okio.source(rawSocket)

public static Source source(Socket socket) throws IOException { if (socket == null) throw new IllegalArgumentException("socket == null"); AsyncTimeout timeout = timeout(socket); //此處用socket的inputstream創(chuàng)建了source Source source = source(socket.getInputStream(), timeout); return timeout.source(source); }//下面請看 okio 是如何將 inputstream 封裝成 source 的private static Source source(final InputStream in, final Timeout timeout) { if (in == null) throw new IllegalArgumentException("in == null"); if (timeout == null) throw new IllegalArgumentException("timeout == null"); return new Source() { @Override public long read(Buffer sink, long byteCount) throws IOException { if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount); if (byteCount == 0) return 0; try { //每次read都會檢測timeout timeout.throwIfReached(); Segment tail = sink.writableSegment(1); int maxToCopy = (int) Math.min(byteCount, Segment.SIZE - tail.limit); //本質還是調用了inputstream的read方法 int bytesRead = in.read(tail.data, tail.limit, maxToCopy); if (bytesRead == -1) return -1; tail.limit += bytesRead; sink.size += bytesRead; return bytesRead; } catch (AssertionError e) { if (isAndroidGetsocknameError(e)) throw new IOException(e); throw e; } } @Override public void close() throws IOException { in.close(); } @Override public Timeout timeout() { return timeout; } @Override public String toString() { return "source(" + in + ")"; } }; }

BufferedSink的創(chuàng)建

跟BuffedSource很相似, 簡略描述

sink = Okio.buffer(Okio.sink(rawSocket));

同樣主要看Okio.sink(rawSocket)的實現(xiàn)

public static Sink sink(Socket socket) throws IOException { if (socket == null) throw new IllegalArgumentException("socket == null"); AsyncTimeout timeout = timeout(socket); //用socket的outputstream創(chuàng)建sink Sink sink = sink(socket.getOutputStream(), timeout); return timeout.sink(sink); }

sink靜態(tài)方法的實現(xiàn)

private static Sink sink(final OutputStream out, final Timeout timeout) { if (out == null) throw new IllegalArgumentException("out == null"); if (timeout == null) throw new IllegalArgumentException("timeout == null"); return new Sink() { @Override public void write(Buffer source, long byteCount) throws IOException { checkOffsetAndCount(source.size, 0, byteCount); while (byteCount > 0) { //每次write之前檢測timeout timeout.throwIfReached(); Segment head = source.head; int toCopy = (int) Math.min(byteCount, head.limit - head.pos); //最終調用outputstream的write方法 out.write(head.data, head.pos, toCopy); head.pos += toCopy; byteCount -= toCopy; source.size -= toCopy; if (head.pos == head.limit) { source.head = head.pop(); SegmentPool.recycle(head); } } } @Override public void flush() throws IOException { out.flush(); } @Override public void close() throws IOException { out.close(); } @Override public Timeout timeout() { return timeout; } @Override public String toString() { return "sink(" + out + ")"; } }; }

寫在最后:

碼字不易看到最后了,那就點個關注唄,只收藏不點關注的都是在耍流氓!

關注并私信我“架構”,免費送一些Java架構資料,先到先得!記得轉發(fā)哦!

以上就是關于pos機98交易超時,okhttp Timeout 超時設置與用法解釋的知識,后面我們會繼續(xù)為大家整理關于pos機98交易超時的知識,希望能夠幫助到大家!

轉發(fā)請帶上網址:http://www.tjfsxbj.com/newsone/53803.html

你可能會喜歡:

版權聲明:本文內容由互聯(lián)網用戶自發(fā)貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權/違法違規(guī)的內容, 請發(fā)送郵件至 babsan@163.com 舉報,一經查實,本站將立刻刪除。