Goのnet.TCPConnの話/shibuya.go01

 Goのnet.TCPConnの話/shibuya.go01

6e8d1cd646b7cc589fdd5bdea0fd9bf1?s=128

shunsukeaihara

February 09, 2016
Tweet

Transcript

  1. Goのnet.TCPConnの話 Shibuya.go  #01   @shunsukeaihara  

  2. とりあえず •  @shunsukeaihara   –  フリーランス.    組み込み向け信号処理理  〜~  分散機械学習とか

      •  最近のGolang仕事   –  ウェアラブルトランシーバー向けVoIPサーバ   –  家庭⽤用ロボットの制御系・⾳音声信号処理理周り   –  アドネットワーク・メディア向け広告配信サーバ   –  ファイル転送サーバ/クライアント
  3. BONX アウトドアスポーツ向けのモバイル回線利利⽤用の複数⼈人で同時に   会話出来るbluetoothウェアラブルトランシーバー

  4. Golangでアウトドア向けVoIPサーバを書く •  途中から開発を引き継ぐことに •  C++で書いてた時代と⽐比べると書くの楽で動作もそこそこ早い   •  帯域・パケットロスが酷い所と安定した所を⾏行行ったり来たりする場 合でも違和感の無い会話・通信の復復帰が出来るようにしないといけ ない

      •  ⾳音声パケット/制御コマンドはサーバ経由の実装   –  アウトドア向けなので回線品質が⼼心配  
  5. サーバとGorou?ne構成

  6. net.TCPConnの挙動でハマる •  制御コマンドのブロードキャ ストや死活監視はTCP   •  ⾮非同期のTCPソケットなので安 ⼼心してたらネットワーク環境 が良良い所にいるクライアント の挙動が不不安定に

      •  雪⼭山でのフィールドテスト 時、⻑⾧長期間ネットが不不安定 な場合で始めて再現 packet  lossしまくる 環境に移動 コマンド送信したクライアントのSocketか ら読みだしているgorutineが固まって⾃自前 のpingタイムアウトで追い出されたり
  7. net.TCPConnはBlockする可能性がある •  TCPConnも、Socket  Bufferが溢れている場合、errにEAGAINが返ると思っ て、プロトタイプ時はそこでsokcetをcloseすればいいと思っていた   •  hFps://golang.org/src/net/fd_unix.go#L310   • 

    BufferがあくまでWaitしている      if  err  ==  syscall.EAGAIN  {          if  err  =  fd.pd.WaitWrite();  err  ==  nil  {            con?nue          }        }
  8. ソケットバッファを⼤大きくするのは……… •  Linux  2.6系のBufferはデフォルトで110k   –  もっと⼤大きくすれば改善する   –  pingタイムアウトの処理理も⼊入れているので詰まる前にsocketを閉

    じることが出来るかもしれないけど……   •  プログラムレベルで待つか捨てるかしないとブロックする  
  9. 絶対にブロックさせたくない場合は •  (対処1)⾃自前でMessageQueueを挟む   •  (対処2)ブロックしないchannelを使う

  10. (対処1)⾃自前でMessageQueueを挟む •  Cとかでやってた普通の対処をしないといけない   –  書き込むときはqueueにenqueueするだけにして⼀一つのgorou?ne でWriteとかFlush   –  enqueueとdequeueだけMutexで囲う

  11. (対処2)ブロックしないchannelを使う •  channelもブロックする可能性は有るけど   func  (ch  *HogeChan)    buffer(){  

    var  next  interface{}   for  {    select{    case  data  :=  <-­‐  ch.inChan:      ch.queue.Enqueue(data)    case  ch.outChan  <-­‐  next:      ch.queue.Dequeue()    }    if  ch.queue.Length()  >  0{      next  =  ch.queue.Peak()    }else{      next  =  nil    }   }   }   •  queueを持ったgorou?neを間に噛ま せばブロックしない   •  参考   –  hFps://github.com/eapache/channels 後ろが詰まっている時はこのcaseが呼ばれず常に inputの⽅方のcaseが呼ばれてselect抜けるので inChanへの書き込みがブロックしなくなる 擬似コードなのでそのまま使っちゃダメ
  12. まとめ •  Goのnet.TCPConnは⽣生のSocketとは挙動が違う   •  複数のSocketを繋いでrou?ngするような処理理を書くときはブロック することに気をつけよう   •  channelというprimi?veは偉⼤大なので活⽤用しよう(そんなに遅くない

    よ!)   –  Capasity関係なくロックしないようにも出来るよ