サーバーにアクセスが無くなったら自動でシャットダウン2017年02月23日 14:18

はじめにお読みください。→当サイトのリンクと免責事項

サーバーは基本常時オンが通常と思いますが、電気代がもったいないので常時オフとします。
サーバーのダウンはクライアントのアクセスが無くなった後サーバー自身がシャットダウンすることとします。
基本はハードディスクのアクセスを管理してアクセスのない時間が10分を超えたらシャットダウンします。
VB.NETで作りますがサービスとして開発するには無償のVS Express2013 for DesktopではWindowsサービス テンプレート が出てきません。仕方がないのでコンソール アプリケーションで開発しタスク スケジューラでPC起動時に実行するようにします。
コンソール アプリケーションのソースです。
Imports System
Imports System.IO
Imports System.Text
Module Module1
    Dim stop_code As Integer = 0
    Sub Main()
        'コンピュータ名
        '"."はローカルコンピュータを表す
        'コンピュータ名は省略可能(省略時は".")
        Dim machineName As String = "."
        'カテゴリ名
        Dim categoryName As String = "PhysicalDisk"
        'カウンタ名
        Dim counterName As String = "Disk Transfers/sec"
        'インスタンス名
        Dim instanceName As String = "2 K: L:"
        'PerformanceCounterオブジェクトの作成
        Dim pc As New System.Diagnostics.PerformanceCounter( _
            categoryName, counterName, instanceName, machineName)
        TextWite()
        Do
            TextRead()
            If pc.NextValue() * 1000 <> 0 Then
                TextWite()
            End If
            System.Threading.Thread.Sleep(10)
        Loop Until stop_code = 1
        End
    End Sub
    Public Sub TextWite()
        Dim fileName As String = "C:\TEMP\ShutDownCounter.txt"
        'ファイルを開く
        Dim fs As New System.IO.FileStream(fileName, _
            System.IO.FileMode.Open, _
            System.IO.FileAccess.Write, _
            System.IO.FileShare.ReadWrite)
        'FileStreamを基にしたStringReaderのインスタンスを作成
        Dim enc As System.Text.Encoding = _
            System.Text.Encoding.GetEncoding("shift_jis")

'************************************ ここからは単に時刻の固定長テキストを作っている
        Dim dNOW As System.DateTime = System.DateTime.Now
        Dim syesre_ As String
        Dim smanth_ As String
        Dim sday_ As String
        Dim shour_ As String
        Dim sminute_ As String
        Dim ssecnd_ As String
        Dim smanth As String
        Dim sday As String
        Dim shour As String
        Dim sminute As String
        Dim ssecnd As String
        Dim sdatetime As String
        syesre_ = dNOW.Year.ToString
        smanth_ = dNOW.Month.ToString
        sday_ = dNOW.Day.ToString
        shour_ = dNOW.Hour.ToString()
        sminute_ = dNOW.Minute.ToString
        ssecnd_ = dNOW.Second.ToString
        smanth_ = "0" & smanth_
        sday_ = "0" & sday_
        shour_ = "0" & shour_
        sminute_ = "0" & sminute_
        ssecnd_ = "0" & ssecnd_
        smanth = smanth_.Substring(Len(smanth_) - 2, 2)
        sday = sday_.Substring(Len(sday_) - 2, 2)
        shour = shour_.Substring(Len(shour_) - 2, 2)
        sminute = sminute_.Substring(Len(sminute_) - 2, 2)
        ssecnd = ssecnd_.Substring(Len(ssecnd_) - 2, 2)
        sdatetime = syesre_ & "/" & smanth & "/" & sday & " " & shour & ":" & sminute & ":" & ssecnd
'******************************************************************************
        Using sw As New System.IO.StreamWriter(fs, enc)
            sw.Write(sdatetime)
        End Using
    End Sub
    Public Sub TextRead()
        Dim s As String
        Dim diffmin As Integer
        '読み込むファイルの名前
        Dim fileName As String = "C:\TEMP\ShutDownCounter.txt"
        'ファイルを開く
        Dim fs As New System.IO.FileStream(fileName, _
            System.IO.FileMode.Open, _
            System.IO.FileAccess.Read, _
            System.IO.FileShare.ReadWrite)
        'FileStreamを基にしたStringReaderのインスタンスを作成
        Dim enc As System.Text.Encoding = _
            System.Text.Encoding.GetEncoding("shift_jis")
        Using sr As New System.IO.StreamReader(fs, enc)
            s = sr.ReadToEnd()
        End Using
        Dim c1 As Char = s(0)
        If s(0) = "S" Then
            stop_code = 1
        Else
            Dim dt1 As DateTime = DateTime.Parse(s)
            diffmin = DateDiff("n", dt1, Now)
            If diffmin > 9 Then
                stop_code = 1
                Dim psi As New System.Diagnostics.ProcessStartInfo()
                Dim p As Process
                psi.FileName = "shutdown.exe"
                'コマンドラインを指定
                psi.Arguments = "/s"
                'ウィンドウを表示しないようにする
                '               psi.UseShellExecute = True
                psi.CreateNoWindow = True
                p = Process.Start(psi)
            End If
        End If
    End Sub
End Module
ご覧のようにPerformanceCounterを使っています。10mSごとに見に行きDisk Transfers/secがゼロでなければアクセス有と判断してC:\TEMP\ShutDownCounter.txtに時刻を書き込みます。見ているHDDは2 K: L:でこれにはEmbyサーバーのコンテンツがあります。
当初10mSより長かったのですが、写真を閲覧している時など検出できない時がありました。動画の再生なら常にアクセスしていますがMP3の再生ではかなり減り、写真などは1回のアクセスで全写真を読み込んでいると思われるほど少ないです。

########################################################################################
ところでEmbyサーバーですがコンテンツは2 K: L:のハードディスクにありますが、トランスコードが始まると2 K: L:のハードディスクには行きません。該当コンテンツのフォーマットを変更し終えればアプリが使っているキャッシュにフォーマット変更後のコンテンツが蓄えられます。以降そのキャッシュにアクセスしてデータを送り出します。フォーマットの変更中はCPU100%です(Intel QSVを使用すれば60%くらい)が完了すればCPU使用率は下がってきます。
トランスコードが行われるのは例えばDLNAプレーヤがH264対応でコンテンツがH265の場合とコンテンツの解像度を落として送信する場合です。例えばクライアント側で1080Pから720Pにした場合などです。
########################################################################################

後述しますが別プログラムでもC:\TEMP\ShutDownCounter.txtに読み書きします。そのため競合の問題が出たためSystem.IO.FileShare.ReadWriteとして共有ファイルにしました。
このコンソールアプリをタスク スケジューラでPC起動時実行するように設定します。



さて、このサーバーマシンですが日常使いでもあります。何もしないでいると10分後には勝手にシャットダウンします。これでは困るのでログインしたらシャットダウンする前にC:\TEMP\ShutDownCounter.txtを更新するアプリを作成し、スタートアップにいれてログインと同時に起動します。

こちらは1分ごとにC:\TEMP\ShutDownCounter.txtを見に行きます。サーバーへのアクセスが無くなって4分したら黄色に7分したら赤になります。8分経ったらC:\TEMP\ShutDownCounter.txtの値を下のTextBoxに退避して、新たに現在時刻をC:\TEMP\ShutDownCounter.txtに書き込みます。
これを繰り返すことで10分のシャットダウンを免れています。
もしEmbyのコンテンツにアクセスがあれば警告音で知らせます。この時全ての色は白になります。
PCでの作業が終わってログアウトする時に色がついていれば最低でも4分間はサーバーへのアクセスが無かったと判断されますのでシャットダウンで終了しても構いません。もし全てが白だったらどなたかがサーバーにアクセスしている可能性もあるのでサインアウトします。サーバーへのアクセスが無くなれば10分後にシャットダウンします。

VB.NETのソースです。
Imports System.IO
Imports System.Text
Imports System.Threading
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim diffmin As Integer
        Dim ts1 As New TimeSpan(0, 0, 2, 0)
        Timer1.Interval = 60000
        Timer1.Start()
        Button1.BackColor = Color.White
        Button2.BackColor = Color.White
        Button3.BackColor = Color.White
        Button4.BackColor = Color.White
        '読み込むファイルの名前
        Dim fileName As String = "C:\TEMP\ShutDownCounter.txt"
        Dim s As String
        'ファイルを開く
        Dim fs As New System.IO.FileStream(fileName, _
            System.IO.FileMode.Open, _
            System.IO.FileAccess.Read, _
            System.IO.FileShare.ReadWrite)
        'FileStreamを基にしたStringReaderのインスタンスを作成
        Dim enc As System.Text.Encoding = _
            System.Text.Encoding.GetEncoding("shift_jis")
        Using sr As New System.IO.StreamReader(fs, enc)
            s = sr.ReadToEnd()
        End Using
        Dim dt1 As DateTime = DateTime.Parse(s)
        diffmin = DateDiff("n", dt1, Now)
        If diffmin > 30 Then
            Dim dt2 As DateTime = Now - ts1
            s = dt2.ToString
           TextWite(dt2)
        End If
        TextBox1.Text = s
    End Sub
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Dim s As String
        Dim diffmin As Integer
        '読み込むファイルの名前
        Dim fileName As String = "C:\TEMP\ShutDownCounter.txt"
        'ファイルを開く
        Dim fs As New System.IO.FileStream(fileName, _
            System.IO.FileMode.Open, _
            System.IO.FileAccess.Read, _
            System.IO.FileShare.ReadWrite)
        'FileStreamを基にしたStringReaderのインスタンスを作成
        Dim enc As System.Text.Encoding = _
            System.Text.Encoding.GetEncoding("shift_jis")
        Using sr As New System.IO.StreamReader(fs, enc)
            s = sr.ReadToEnd()
        End Using
        TextBox1.Text = s
        Dim dt1 As DateTime = datetime.Parse(s)

        diffmin = DateDiff("n", dt1, Now)
        If diffmin < 1 Then
            Button2.BackColor = Color.White '外部アクセスがあり初期状態にする
            Button3.BackColor = Color.White '外部アクセスがあり初期状態にする
            Button4.BackColor = Color.White '外部アクセスがあり初期状態にする
            Button1.BackColor = Color.White   '外部アクセスがありブリンクする
            System.Threading.Thread.Sleep(1000)
            System.Media.SystemSounds.Beep.Play() '外部アクセスがあり警告音鳴動
            System.Threading.Thread.Sleep(1000)
            System.Media.SystemSounds.Beep.Play()
            System.Threading.Thread.Sleep(1000)
            System.Media.SystemSounds.Beep.Play()
        End If
        If diffmin > 3 Then
            Button1.BackColor = Color.Yellow
        End If
        If diffmin > 6 Then
            Button1.BackColor = Color.Red
        End If
        If diffmin > 7 Then
            If Button2.BackColor = Color.White Then
                Button2.BackColor = Color.Blue
            Else
                If Button3.BackColor = Color.White Then
                    Button3.BackColor = Color.Blue
                Else
                    If Button4.BackColor = Color.White Then
                        Button4.BackColor = Color.Blue
                    Else
                        Button3.BackColor = Color.White
                        Button4.BackColor = Color.White
                    End If
                End If
            End If

            Button1.BackColor = Color.White
            TextBox2.Text = TextBox1.Text
            TextWite(Now)
        End If
    End Sub
    Public Sub TextWite(datetime_ As Date)
        Dim fileName As String = "C:\TEMP\ShutDownCounter.txt"
        'ファイルを開く
        Dim fs As New System.IO.FileStream(fileName, _
            System.IO.FileMode.Open, _
            System.IO.FileAccess.Write, _
            System.IO.FileShare.ReadWrite)
        'FileStreamを基にしたStringReaderのインスタンスを作成
        Dim enc As System.Text.Encoding = _
            System.Text.Encoding.GetEncoding("shift_jis")

'************************************* ここからは単に時刻の固定長テキストを作っている
        Dim syesre_ As String
        Dim smanth_ As String
        Dim sday_ As String
        Dim shour_ As String
        Dim sminute_ As String
        Dim ssecnd_ As String
        Dim smanth As String
        Dim sday As String
        Dim shour As String
        Dim sminute As String
        Dim ssecnd As String
        Dim sdatetime As String
        syesre_ = datetime_.Year.ToString
        smanth_ = datetime_.Month.ToString
        sday_ = datetime_.Day.ToString
        shour_ = datetime_.Hour.ToString()
        sminute_ = datetime_.Minute.ToString
        ssecnd_ = datetime_.Second.ToString
        smanth_ = "0" & smanth_
        sday_ = "0" & sday_
        shour_ = "0" & shour_
        sminute_ = "0" & sminute_
        ssecnd_ = "0" & ssecnd_
        smanth = smanth_.Substring(Len(smanth_) - 2, 2)
        sday = sday_.Substring(Len(sday_) - 2, 2)
        shour = shour_.Substring(Len(shour_) - 2, 2)
        sminute = sminute_.Substring(Len(sminute_) - 2, 2)
        ssecnd = ssecnd_.Substring(Len(ssecnd_) - 2, 2)
        sdatetime = syesre_ & "/" & smanth & "/" & sday & " " & shour & ":" & sminute & ":" & ssecnd
'*****************************************************************************
        Using sw As New System.IO.StreamWriter(fs, enc)
            sw.Write(sdatetime)
        End Using
    End Sub
End Class

当初はアクセスが無くなり30分後にシャットダウンするように作ったのですがアクセス終了後15分くらいで1回アクセスがあります。おそらく電源オプションでHDD電源を切るを20分に設定しているためではないかと考えています。結局30分に設定しても45分から50分くらい経ったあとでシャットダウンします。
10分に設定すればそれらの合間をぬって落ちてくれます。
PCを使っていてもkまたはLのドライブにアクセスがあれば警告音がでますので一耳瞭然です。

コメント

トラックバック