サーバーにアクセスが無くなったら自動でシャットダウン ― 2017年02月23日 14:18
はじめにお読みください。→当サイトのリンクと免責事項
サーバーは基本常時オンが通常と思いますが、電気代がもったいないので常時オフとします。
サーバーのダウンはクライアントのアクセスが無くなった後サーバー自身がシャットダウンすることとします。
基本はハードディスクのアクセスを管理してアクセスのない時間が10分を超えたらシャットダウンします。
VB.NETで作りますがサービスとして開発するには無償のVS Express2013 for DesktopではWindowsサービス テンプレート が出てきません。仕方がないのでコンソール アプリケーションで開発しタスク スケジューラでPC起動時に実行するようにします。
コンソール アプリケーションのソースです。
Imports System
Imports System.IO
Imports System.Text
Module Module1
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:"
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()
Dim pc As New System.Diagnostics.PerformanceCounter( _
categoryName, counterName, instanceName, machineName)
TextWite()
Do
TextRead()
If pc.NextValue() * 1000 <> 0 Then
TextWite()
End If
TextRead()
If pc.NextValue() * 1000 <> 0 Then
TextWite()
End If
System.Threading.Thread.Sleep(10)
Loop Until stop_code = 1
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")
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
'******************************************************************************
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
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)
'読み込むファイルの名前
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)
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
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
Imports System.Text
Imports System.Threading
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
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
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
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 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 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()
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 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
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
Button4.BackColor = Color.White
End If
End If
End If
End If
End If
Button1.BackColor = Color.White
TextBox2.Text = TextBox1.Text
TextWite(Now)
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")
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
'*****************************************************************************
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
sw.Write(sdatetime)
End Using
End Sub
End Class
当初はアクセスが無くなり30分後にシャットダウンするように作ったのですがアクセス終了後15分くらいで1回アクセスがあります。おそらく電源オプションでHDD電源を切るを20分に設定しているためではないかと考えています。結局30分に設定しても45分から50分くらい経ったあとでシャットダウンします。
10分に設定すればそれらの合間をぬって落ちてくれます。
PCを使っていてもkまたはLのドライブにアクセスがあれば警告音がでますので一耳瞭然です。