Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

とりあえず •  @shunsukeaihara   –  フリーランス.    組み込み向け信号処理理  〜~  分散機械学習とか   •  最近のGolang仕事   –  ウェアラブルトランシーバー向けVoIPサーバ   –  家庭⽤用ロボットの制御系・⾳音声信号処理理周り   –  アドネットワーク・メディア向け広告配信サーバ   –  ファイル転送サーバ/クライアント

Slide 3

Slide 3 text

BONX アウトドアスポーツ向けのモバイル回線利利⽤用の複数⼈人で同時に   会話出来るbluetoothウェアラブルトランシーバー

Slide 4

Slide 4 text

Golangでアウトドア向けVoIPサーバを書く •  途中から開発を引き継ぐことに •  C++で書いてた時代と⽐比べると書くの楽で動作もそこそこ早い   •  帯域・パケットロスが酷い所と安定した所を⾏行行ったり来たりする場 合でも違和感の無い会話・通信の復復帰が出来るようにしないといけ ない   •  ⾳音声パケット/制御コマンドはサーバ経由の実装   –  アウトドア向けなので回線品質が⼼心配  

Slide 5

Slide 5 text

サーバとGorou?ne構成

Slide 6

Slide 6 text

net.TCPConnの挙動でハマる •  制御コマンドのブロードキャ ストや死活監視はTCP   •  ⾮非同期のTCPソケットなので安 ⼼心してたらネットワーク環境 が良良い所にいるクライアント の挙動が不不安定に   •  雪⼭山でのフィールドテスト 時、⻑⾧長期間ネットが不不安定 な場合で始めて再現 packet  lossしまくる 環境に移動 コマンド送信したクライアントのSocketか ら読みだしているgorutineが固まって⾃自前 のpingタイムアウトで追い出されたり

Slide 7

Slide 7 text

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          }        }

Slide 8

Slide 8 text

ソケットバッファを⼤大きくするのは……… •  Linux  2.6系のBufferはデフォルトで110k   –  もっと⼤大きくすれば改善する   –  pingタイムアウトの処理理も⼊入れているので詰まる前にsocketを閉 じることが出来るかもしれないけど……   •  プログラムレベルで待つか捨てるかしないとブロックする  

Slide 9

Slide 9 text

絶対にブロックさせたくない場合は •  (対処1)⾃自前でMessageQueueを挟む   •  (対処2)ブロックしないchannelを使う

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

(対処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への書き込みがブロックしなくなる 擬似コードなのでそのまま使っちゃダメ

Slide 12

Slide 12 text

まとめ •  Goのnet.TCPConnは⽣生のSocketとは挙動が違う   •  複数のSocketを繋いでrou?ngするような処理理を書くときはブロック することに気をつけよう   •  channelというprimi?veは偉⼤大なので活⽤用しよう(そんなに遅くない よ!)   –  Capasity関係なくロックしないようにも出来るよ