Go package to simulate bandwidth, latency and packet loss for net.PacketConn and net.Conn interfaces.
Its main usage is to test robustness of applications and network protocols run over unreliable transport protocols such as UDP or IP.As a side benefit, it can also be used as outbound bandwidth limiter.
lossy only alters the writing side of the connection, reading side is kept as it is.
package mainimport ("fmt""github.com/cevatbarisyilmaz/lossy""log""math/rand""net""time")constpacketSize=64funcmain() {// Create two connection endpoints over UDPpacketConn,conn:=createConnections()// Create a lossy packet connectionbandwidth:=1048// 8 Kbit/sminLatency:=100*time.MillisecondmaxLatency:=time.SecondpacketLossRate:=0.33headerOverhead:=lossy.UDPv4MinHeaderOverheadlossyPacketConn:=lossy.NewPacketConn(packetConn,bandwidth,minLatency,maxLatency,packetLossRate,headerOverhead)// Write some packets via lossyvarbytesWrittenintconstpacketCount=32gofunc() {fori:=0;i<packetCount;i++ {packet:=createPacket()_,err:=lossyPacketConn.WriteTo(packet,conn.LocalAddr())iferr!=nil {log.Fatal(err)}bytesWritten+=len(packet)+headerOverhead}fmt.Println("Sent",packetCount,"packets with total size of",bytesWritten,"bytes")baseTransmissionDuration:=time.Duration(float64(bytesWritten*int(time.Second))/float64(bandwidth))earliestCompletion:=baseTransmissionDuration+minLatencylatestCompletion:=baseTransmissionDuration+maxLatencyfmt.Println("Expected transmission duration is between",earliestCompletion,"and",latestCompletion)}()// Read packets at the other sideconsttimeout=3*time.Secondvarpackets,bytesReadintstartTime:=time.Now()for {_=conn.SetReadDeadline(time.Now().Add(timeout))buffer:=make([]byte,packetSize)n,err:=conn.Read(buffer)iferr!=nil {break}bytesRead+=n+headerOverheadpackets++}dur:=time.Now().Sub(startTime)-timeoutfmt.Println("Received",packets,"packets with total size of",bytesRead,"bytes in",dur)// Close the connections_=lossyPacketConn.Close()_=conn.Close()}funccreateConnections() (net.PacketConn, net.Conn) {packetConn,err:=net.ListenUDP("udp",&net.UDPAddr{IP:net.IPv4(127,0,0,1),Port:0,})iferr!=nil {log.Fatal(err)}conn,err:=net.DialUDP("udp",nil,packetConn.LocalAddr().(*net.UDPAddr))iferr!=nil {log.Fatal(err)}returnpacketConn,conn}funccreatePacket() []byte {packet:=make([]byte,packetSize)rand.Read(packet)returnpacket}