如何解決TCP socket的阻塞問題
解決TCP socket的阻塞問題
大傢知道,tcp的讀和寫是阻塞的,即讀的時候不知道什麼時候讀完,寫的時候不知道什麼時候寫完,因此線程就一直暫停在哪裡,一般tcp程序用在上位機下位機之間對吧!
下位機一些設備一般會發心跳報文給我們機器,假設為10s發一次吧,當機器超過10s沒接收到數據,那麼我們就要考慮把socket斷開,因為不斷開的話設備重新連接可能又會建立新的socket,這樣如果設備反復斷開連接的話,將產生大量的socket,占用大量系統資源,這裡我們用socket.setSoTimeout(500)方法解決read方法的阻塞問題,同時設定一個標志位
在異常處理程序當中退出socket連接
public void run(){ InputStream is = null; OutputStream os = null; int flag = 0; try { socket.setSoTimeout(500); // 0.5秒就退出read()方法的阻塞 is = socket.getInputStream(); os = socket.getOutputStream(); } catch (Exception e2) { e2.printStackTrace(); } while (true) { try { // 讀取數據 int readlen = is.read(buff); if (readlen > 0) { flag = 0; } byte data[] = Arrays.copyOfRange(buff, 0, readlen); resolveData(data); } catch (IOException e) { try { flag++; if (flag == 200) { is.close(); os.close(); socket.close(); } } catch (Exception e1) { e1.printStackTrace(); } } } }
TCP連接阻塞的監控和處理
那麼,什麼樣的TCP連接屬於上述發生阻塞的異常連接呢?結合線上運維經驗
我們整理出符合該類異常的特征如下
- 該連接的Recv_Q的值特別大(超過3M)
- 該連接的Recv_Q的值持續上漲,造成堆積(在一定滑動時間窗口內)
- 服務端進程已長時間不再處理該連接的請求(超過90秒)
其中Recv_Q的值可以通過netstat或ss系統工具即可進行Recv_Q隊列大小的采樣,從而進行閥值判斷。
netstat 的結果是讀取/proc/net/tcp文件而來的.
如何查看一個連接的創建時間
1.nestat -apn | grep xxx查看到對應的連接的進程pid和端口
2. 將上下遊端口,轉換為16進制xxxa xxxb
3.然後cat /proc/net/tcp | grep -i xxxa | grep -i xxxb找到該socket連接的inode inodex
4.ls -al /proc/pid/fd | grep inodex即可看見該socket文件的創建時間.
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Java網絡編程TCP實現聊天功能
- java中Socket設置超時時間的兩種方式
- java面試try-with-resources問題解答
- Java中Socket用法詳解
- idea中使用Inputstream流導致中文亂碼解決方法