2013-10-29 22 views
7

私は単純なUDPサーバをgoに書いています。golang UDPサーバの奇妙な動作

私がgo run udp.goを送信すると、送信したすべてのパッケージが印刷されます。しかし、go run udp.go > outを実行すると、クライアントが停止するとoutファイルにstdoutが渡されなくなります。

クライアントは、10k要求を送信する単純なプログラムです。したがって、ファイルには、送信されるパッケージの約50%があります。クライアントを再実行すると、クライアントスクリプトが終了するまでファイルoutが再び大きくなります。

Serverコード:

package main 

import (
    "net" 

    "fmt" 
) 

func main() { 
    addr, _ := net.ResolveUDPAddr("udp", ":2000") 
    sock, _ := net.ListenUDP("udp", addr) 

    i := 0 
    for { 
    i++ 
    buf := make([]byte, 1024) 
    rlen, _, err := sock.ReadFromUDP(buf) 
    if err != nil { 
     fmt.Println(err) 
    } 
    fmt.Println(string(buf[0:rlen])) 
    fmt.Println(i) 
    //go handlePacket(buf, rlen) 
    } 
} 

そして、ここでは、クライアントコードは次のとおりです。

package main 

import (
    "net" 

    "fmt" 
) 

func main() { 

    num := 0 
    for i := 0; i < 100; i++ { 
    for j := 0; j < 100; j++ { 
     num++ 
     con, _ := net.Dial("udp", "127.0.0.1:2000") 
     fmt.Println(num) 
     buf := []byte("bla bla bla I am the packet") 
     _, err := con.Write(buf) 
     if err != nil { 
     fmt.Println(err) 
     } 
    } 
    } 
} 
+0

クライアントとサーバーの両方で、いくつかの考えられるエラーを無視しています。クライアントを実行すると、すぐに実行時エラーが発生しました。エラーチェックを追加した後: "dial udp 127.0.0.1:2000:開いているファイルが多すぎます"。あなたの問題が関連しているかどうかわからない場合は、すべての可能性のあるエラーのチェックを追加するように依頼し、それがあなたの問題の解決につながっていない場合は、結果をここに戻してください:) – fresskoma

+0

Iエラーチェックを追加し、そのような問題はありません。クライアントが動作し、別のサーバーでテストしました。それは、リダイレクションがソケットの読み込みに遅れを起こすように見え、いくつかのパケットは見逃しています.... –

答えて

11

あなたが疑われるとして、それが原因UDPの性質上UDPパケットロスのように思えます。 UDPはコネクションレスなので、クライアントはサーバーが利用可能であるか、データを受信する準備ができているかどうかは気にしません。したがって、サーバーがビジー処理中の場合は、次の着信データグラムを処理できません。 netstat -u(UDPパケット損失情報を含める必要があります)で確認できます。私はサーバー(受信側)が送信されたパケットに追いつけなかった同じことに遭遇しました。

コールSetReadBuffer:

次の2つのもの(第2あなたの例で私のために働いていた)を試すことができます。受信ソケットには、送信するすべてのものを処理するのに十分なバッファリングがあることを確認してください。

sock, _ := net.ListenUDP("udp", addr) 
sock.SetReadBuffer(1048576) 

すべてのパケット処理は一貫したルーチンで行います。受信に使用できるようにするためにサーバーが他の作業をしていないことを確認して、1秒あたりのデータグラムを増やしてください。つまり、処理作業を実行ルーチンに移すので、ReadFromUDP()を保持しません。

//Reintroduce your go handlePacket(buf, rlen) with a count param 
func handlePacket(buf []byte, rlen int, count int) 
     fmt.Println(string(buf[0:rlen])) 
     fmt.Println(count) 
} 

...

go handlePacket(buf, rlen, i) 

一つの最後のオプション:

最後に、おそらくない何をしたい、あなたが遅くなると思われるクライアントに睡眠を置く問題を取り除くこともできます。例えば

buf := []byte("bla bla bla I am the packet") 
time.Sleep(100 * time.Millisecond) 
_, err := con.Write(buf) 
+0

ReadFromUDPは、処理を簡素化してチャネルを保存するgoルーチン内から行うことができます。 – Xorlev

1

が書き込み文の後に標準出力を同期してみます。

os.Stdout.Sync() 
+0

私はそれが問題だとは思わない。IMOのstdoutは、受け取ったすべての改行時にフラッシュされるか、アプリケーションは 'exit'を使って正常に終了します。 [manページ](http://linux.die.net/man/3/stdout)を参照してください。 "ストリームstdoutは端末を指しているときにラインバッファされますが、fflush(3)またはexit(3)が呼び出されるか、改行が出力されるまで、部分行は表示されません。 – nemo

+2

「端末を指しているとき」は、正しく動作するケースとそうでないケースがあります。サーバーが終了しないため、終了時にStdoutがフラッシュされません。 –