C# で使える精度の高いタイマー

DateTime.Now とか、Environment.TickCount とか、これらの精度は、せいぜい15~16 ms 程度。
もっと精度が欲しい事もある。
そんなときは、Kernel32 の QueryPerformanceCounter と QueryPerformanceFrequency を使うとよろしい。詳しくは検索すると出てくる。
このクラスは、上記の API をラップしたもの。

using System;
using System.Runtime.InteropServices;
using System.Threading;

public class MyTimer
{
    [DllImport("Kernel32.DLL")]
    private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
    [DllImport("Kernel32.DLL")]
    private static extern bool QueryPerformanceFrequency(out long lpFrequency);

    private long startTime;
    private long stopTime;
    private long freq;

    public MyTimer()
    {
        startTime = 0;
        stopTime = 0;
        if (QueryPerformanceFrequency(out freq) == false)
        {
            throw new Exception();
        }
    }

    public void Start()
    {
        Thread.Sleep(0);
        QueryPerformanceCounter(out startTime);
    }

    public void Stop()
    {
        QueryPerformanceCounter(out stopTime);
    }

    public double Duration
    {
        get
        {
            return (stopTime - startTime) * 1000.0 / freq;
        }
    }
}

C# の TcpClient をハブだけの環境で使うと遅い気がする

.Net Framework には、TcpClient という Socket のラッパっぽい、便利クラスがある。

だが、このクラスを使って、ハブだけのクローズドな環境で利用すると、接続開始してから、何かのタイムアウト待ちで、通信できるまで15秒かかってしまう。
デフォルトゲートウェイがある環境(ルーターがある環境)ではすぐ通信できるが、無い環境では15秒後に通信が始まる。

Socket クラスを使用すると、すぐに通信できるのを見ると TcpClient は恐らく、何らかの処理(名前解決とか?)を行おうとし、そのタイムアウトが15秒に設定してあるためと思われる。

なので、TcpClient と同じようなメソッドを実装したクラスで、既存の TcpClient の実装部分を置き換えることでコレが解決する。
具体的には、以下のようなクラスを作成した。

using System;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace Util
{
    public class TcpClient2
    {
        private IPEndPoint end;
        private Socket socket;
        private NetworkStream stream;
        
        public TcpClient2(string host, int port) : this(IPAddress.Parse(host), port)
        {
        }
        public TcpClient2(IPAddress addr, int port)
        {
            end = new IPEndPoint(addr, port);
        }
        public NetworkStream GetStream()
        {
            if(socket == null)
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, SendTimeout);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ReceiveTimeout);
                socket.Connect(end);
                stream = new NetworkStream(socket);
            }
            return stream;
        }
        public void Close()
        {
            socket.Close();
        }
        public int ReceiveTimeout = 0;
        public int SendTimeout    = 0;
    }
}