標準的な例の「エコー」クライアント/サーバー アプリケーションをできるだけ速く実行しようとしていますが、ネットワークが制限要因になっていると確信しています。1 ギガビットのネットワーク カードを使用していますが、リソース モニターを使用すると、クライアントから 7 メガビットしか取得できません。
ソケット、メッセージ フレーミング、および長さインジケータの基本を理解し、長さインジケータによって示されるすべてのバイトを受信します。キープアライブ パケット、ハーフ オープン接続など。
ストック標準のソケット操作を使用して開始し、次に非同期の使用に切り替えました。(送信を非同期に変更しなかったのは、[知識があるように見える人が影響を与えるべきではないと誰かが言った] ためです) 私はまったく同じパフォーマンスを持っています。同じスレッドで行われます。しかし、私の簡単なテストでは、ループ送信で連続してスピンする 1 つのスレッドと、受信する別のまったく別のスレッドを専用にしました。
私はすべてを試しましたが、どこでより多くのパフォーマンスを得ることができるかについて完全に迷っています. 私は IPerf を使用し、毎秒 1 ギガビットのバック速度を報告し、リソース モニターも帯域幅を食いつぶしていることを示しました。
誰かがより完全な例の方向に私を向けることができたとしても。私が遭遇したもののほとんどは、取るに足らないものか不完全なものです。
これが一般的なコードです。
class Program
{
private static Socket sock;
private static BlockingCollection<string> queue;
private static int bytesReceived;
private static byte[] dataBuffer;
private static readonly byte[] lengthBuffer = new byte[4];
private static byte[] PrependLengthIndicator(byte[] data)
{
return BitConverter.GetBytes(data.Length).Concat(data).ToArray();
}
private static void Receive()
{
if (dataBuffer == null)
{
sock.BeginReceive(lengthBuffer, 0, 4, SocketFlags.None, ReceiveCallback, null);
}
else
{
sock.BeginReceive(dataBuffer, 0, bytesReceived, SocketFlags.None, ReceiveCallback, null);
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
bytesReceived += sock.EndReceive(ar);
if (dataBuffer == null)
{
// Currently receiving length indicator
if (bytesReceived >= 4)
{
var length = BitConverter.ToInt32(lengthBuffer, 0);
dataBuffer = new byte[length];
bytesReceived = 0;
}
}
else
{
if (bytesReceived == dataBuffer.Length)
{
// Finished reading
var request = Encoding.ASCII.GetString(dataBuffer);
dataBuffer = null;
bytesReceived = 0;
queue.Add(request);
}
}
ContinueReading();
}
private static void ContinueReading()
{
// Read into the appropriate buffer: length or data
if (dataBuffer != null)
{
sock.BeginReceive(dataBuffer, bytesReceived, dataBuffer.Length - bytesReceived, SocketFlags.None, ReceiveCallback, null);
}
else
{
sock.BeginReceive(lengthBuffer, bytesReceived, lengthBuffer.Length - bytesReceived, SocketFlags.None, ReceiveCallback, null);
}
}
}
サーバー部分は次のとおりです。
static void Main(string[] args)
{
var listenSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSock.Bind(new IPEndPoint(IPAddress.Parse(ConfigurationManager.AppSettings["LocalIp"]), 3333));
listenSock.Listen(10);
Console.WriteLine("Server started...");
sock = listenSock.Accept();
Console.WriteLine("Connection accepted.");
queue = new BlockingCollection<string>();
Receive();
var count = 0;
var sender = new Thread(() =>
{
while (true)
{
var bar = queue.Take() + "Resp";
count++;
var resp = Encoding.ASCII.GetBytes(bar);
var toSend = PrependLengthIndicator(resp);
if (count % 10000 == 0)
{
Console.WriteLine(bar);
}
sock.Send(toSend);
}
});
sender.Start();
}
クライアント部分は次のとおりです。
static void Main(string[] args)
{
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine("Connecting...");
sock.Connect(IPAddress.Parse(ConfigurationManager.AppSettings["EndPointIp"]), 3333);
Console.WriteLine("Connected.");
Receive();
var count = 0;
while(true)
{
count++;
var foo = "Echo-" + count;
var data = Encoding.ASCII.GetBytes(foo);
var toSend = PrependLengthIndicator(data);
sock.Send(toSend);
}
}