作り方が悪いだけなんだろうか

気づいたらもう冬休み第2弾も終わりか。
Pythonの練習にUDPでパケット投げまくってネットワークのスループットはかるプログラム作ってたんだが、作り方が悪いのかそういうものなのか、同一ホストで測定しててもパケットロスが30% overとかいってる。一応パケット送る方はちゃんと送ってるみたいなので、受信側で落としてるみたいなんだけど、どうにかできんものかなぁ。

追記
もったいないからソース貼る。思いつきで作ってる上にほとんどPython使ったことないのできわめて汚い。
#!/usr/bin/python -O
# -*- coding: utf-8 -*-
import socket
from optparse import OptionParser
from struct import *
from datetime import timedelta, datetime

# パケットのstructモジュールでのフォーマット文字列
HELLO = '!5sII'
OK = '!2s'
DATAHEADER = '!I'

# メイン
def main():
	# コマンドラインオプションの解析
	parser = OptionParser()
	parser.add_option("-s", "--server", dest="servermode",
	                  action="store_true", default=False,
	                  help="server mode")
	parser.add_option("-p", "--port", type="int", dest="port",
	                  help="server port", default=8021)
	parser.add_option("-d", "--destination", dest="destination",
	                  help="destination host")
	parser.add_option("-c", "--count", type="int", dest="count",
	                  help="send number of COUNT datagrams",
	                  default=10000)
	parser.add_option("-l", "--length", type="int", dest="datalength",
	                  help="send LENGTH byte datagram",
	                  default=1500)
	(options, args) = parser.parse_args()
	
	#	 コマンドラインオプションによってモードを切り替えて起動する。
	if options.servermode:
		servermode(options.port)
	else:
		if not options.destination:
			parser.error("client mode is required option -d.")
		clientmode(options.destination, options.port, options.count, options.datalength)

# サーバモード
def servermode(port):
	print "server mode", "port:", port
	
	# ソケット生成
	s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	# NATを超えるために、ソース・デスティネーションポートを固定する。
	# ソース・ディスティネーションポートを同じにするため、
	# 同一ホストでサーバ・クライアントは同居できない。
	# ※ポートをソース・デスティネーションの2種類使えば可能
	s.bind(("", port))
	# Helloパケットを受け取る
	(counter, length) = recievehello(s, port)
	# パケットを受け取る。
	(bps, losscount) = recievepacket(s, port, counter, length)
	# 結果表示
	print "Recieve rate : %d bps" % bps
	print "Loss packets : %d packets (%f %%)" % (losscount, ((losscount * 100.0) / (counter * 1.0)))

# Helloパケットを受け取って、初期データを作る
def recievehello(s, port):
	# タイムアウトは設定しないで待ち続ける。
	# socket#recvfrom()が返すaddressは、
	# アドレスとポートのタプルみたい。
	(recieve_packet, address) = s.recvfrom(calcsize(HELLO))
	(hello, counter, length) = unpack(HELLO, recieve_packet)
	# 一応内容の確認もする。
	if hello != 'hello':
		raise
	# OKパケットを作る。
	ok_packet = pack(OK, 'OK')
	# OKパケットを送る。
	(destination, port) = address
	sending(s, port, destination, ok_packet)
	print "From", address, "count:", counter, "length:", length
	# 送られてくる数とパケットの長さをタプルで返す。
	return (counter, length)


# クライアントからパケットをひたすら受け取る。
def recievepacket(s, port, counter, length):
	print "recieving packets..."
	# 送られてくるデータのフォーマット文字列を作る。
	format_string = dataformat(length)
	# 受信タイムアウトの設定をする。
	s.settimeout(1.0) # 対象ネットワークにより調整の必要あり
	# 受信できたらTrueにする配列を作る。
	recieved = []
	for index in range(counter):
		recieved.append(False)
	packetsize = calcsize(format_string)
	# 開始時刻を取得する。
	start_time = datetime.now()
	# ひたすら受信する。
	try:
		while True:
			(recieve_packet, address) = s.recvfrom(packetsize)
			(index) = unpack(format_string, recieve_packet)
			# 受信したことを記録する。
			recieved[index[0]] = True
	except socket.timeout:
		# タイムアウトの例外は無視。その時点で受信終了。
		pass
	# 送るのにかかった時間を計算する。
	end_time = datetime.now() - timedelta(seconds=-1)
	delta_time = end_time - start_time
	print "start time : %s" % start_time
	print "end time : %s" % end_time
	print "delta time : %s" % delta_time
	# 受信レートを計算する。
	seconds = delta_time.days * 24.0 * 60.0 * 60.0 + delta_time.seconds * 1.0 + delta_time.microseconds / 1000.0
	bits = counter * length * 8.0
	# 受信レート(bps)と消失パケット数をタプルで返す。
	# recieved[0]は必ずFalseなのでカウントから1減らす。
	return (bits / seconds, recieved.count(False) - 1)

# クライアントモード
def clientmode(destination, port, counter, length):
	print "client mode", "destination:", destination, "port:", port, "count:", counter, "length:", length
	
	# ソケット生成
	s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	# NATを超えるために、ソース・デスティネーションポートを固定する。
	# サーバのポートと同じにするため、同一ホストで
	# サーバ・クライアントは同居できない。
	# ※ポートをソース・デスティネーションの2種類使えば可能
#	s.bind(("", port))
	s.bind(("", port + 1)) # とりあえずテスト用。コマンドラインオプション増やすか
	# サーバにHelloパケットを送る
	sayhello(s, port, destination, counter, length)
	# 指定された量のパケットをサーバに送りつける
	bps = sendpacket(s, port, destination, counter, length)
	print "load : %f bps" % bps


# 最初にどんなパケットを送りつけるかをHelloでサーバに知らせる
def sayhello(s, port, destination, counter, length):
	# Helloパケットを組み立てる
	packet = pack(HELLO, 'hello', counter, length)
	# 送りつける
	sending(s, port, destination, packet)
	# OKがくるまでのタイムアウトを設定
	s.settimeout(1.0)
	# 戻りパケットは2バイト(OK)
	(recieve_packet, address) = s.recvfrom(calcsize(OK))
	# 一応中身を検査
	(recieve) = unpack(OK, recieve_packet)
	if recieve[0] != 'OK':
		raise

# 指定された量のパケットをサーバに送りつける。
def sendpacket(s, port, destination, counter, length):
	print "sending packets..."
	# 送りつけるパケットを作るためのフォーマット文字列を作る。
	format_string = dataformat(length)
	# 開始時刻を取得する。
	start_time = datetime.now()
	# 送りつける
	packet_number = 1
	while packet_number != counter:
		data = pack(format_string, packet_number)
		sending(s, port, destination, data)
		packet_number += 1
	# 完了時刻を取得する。
	end_time = datetime.now()
	# 送るのにかかった時間を計算する。
	delta_time = end_time - start_time
	print "start time : %s" % start_time
	print "end time : %s" % end_time
	print "delta time : %s" % delta_time
	# 実際にかけた負荷をbps単位で返す。
	seconds = delta_time.days * 24.0 * 60.0 * 60.0 + delta_time.seconds * 1.0 + delta_time.microseconds / 1000.0
	bits = counter * length * 8.0
	return bits / seconds


# どうもWindowsはこういうことしないとちゃんと送ってくれないみたい
# from Pythonクックブック p.496
def sending(s, port, destination, data):
	while data:
		bytes_sent = s.sendto(data, (destination, port))
		data = data[bytes_sent:]

# 送りつけるパケットを作るためのフォーマット文字列を作る。
def dataformat(length):
	datalength = length - calcsize(DATAHEADER)
	return "%s%d%s" % (DATAHEADER, datalength, 'x')

# いつもの
if __name__ == "__main__":
	main()