Skip to content

Instantly share code, notes, and snippets.

@noqisofon
Created December 20, 2010 08:32
Show Gist options
  • Save noqisofon/748155 to your computer and use it in GitHub Desktop.
Save noqisofon/748155 to your computer and use it in GitHub Desktop.
コンピューターが起動しているかどうかを調べたい感じ。
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using spaghetti.util;
using groan.util;
namespace sample.startupnotify.answer {
/// <summary>
///
/// </summary>
class StartupAnswerGuestSample {
/// <summary>
///
/// </summary>
/// <param name="args"></param>
public void run(string[] args) {
int listen_port = LOCAL_PORT - 1;
Encoding encoding = Encoding.UTF8;
/*
* マルチキャストでホストからのパケットを受信します。
*/
UdpClient multicast_client = new UdpClient( LOCAL_PORT, AddressFamily.InterNetwork );
IPAddress group_address = IPAddress.Parse( "239.0.0.0" );
//IPEndPoint group_listen_point = new IPEndPoint( group_address, listen_port );
IPEndPoint listen_point = new IPEndPoint( IPAddress.Any, listen_port );
int loop_count = 0;
bool receive_completed = false;
TimeSpan waitng_time = TimeSpan.FromMilliseconds( 100 );
RequestPacket request = null;
try {
// multicast_client をマルチキャストグループに参加させます。
multicast_client.JoinMulticastGroup( group_address, 50 );
Console.WriteLine( "joined a multicast group." );
Console.Write( "receive: " );
IAsyncResult done = multicast_client.BeginReceive( null, null );
while ( !receive_completed ) {
if ( loop_count >= RECEIVE_LOOP_MAX ) {
/*
* タイムアウトしたらプログラムを終了します。
*/
Console.WriteLine( "receive timed out." );
Console.WriteLine( "host-side program may not yet started." );
break;
}
if ( done.AsyncWaitHandle.WaitOne( waitng_time ) ) {
byte[] received_bytes = multicast_client.EndReceive( done, ref listen_point );
string encoded_text = encoding.GetString( received_bytes );
Console.WriteLine( encoded_text );
Console.WriteLine( "was sent from {0}", listen_point );
request = RequestPacket.deserializeFromXMLString( encoded_text );
/*
* 成功したのに break するのは少しお行儀が悪い気がする。
* なので、ループ続行用フラグを ON にして、continue する。
*/
receive_completed = true;
continue;
}
++loop_count;
}
} finally {
Console.WriteLine( "leave a multicast group." );
multicast_client.DropMulticastGroup( group_address );
}
if ( !receive_completed ) {
Console.WriteLine();
Console.Write( "press enter to exit: " );
Console.ReadLine();
return;
}
Thread.Sleep( 2000 );
TcpClient client = new TcpClient( AddressFamily.InterNetwork );
NetworkStream stream = null;
ResponseSegment segment = new ResponseSegment( 200, "OK" );
try {
Console.WriteLine( "connect." );
client.Connect( listen_point );
if ( client.Connected ) {
Console.WriteLine( "complete connection." );
Console.WriteLine( "sending" );
string segment_text = segment.toXMLString();
byte[] send_bytes = encoding.GetBytes( segment_text );
stream = client.GetStream();
Console.WriteLine( "send: {0}", segment_text );
stream.Write( send_bytes, 0, send_bytes.Length );
Console.WriteLine( "{0} byte sent.", send_bytes.Length );
}
} finally {
if ( stream != null )
stream.Close();
client.Close();
}
Console.WriteLine( "close." );
Console.Write( "press enter to exit: " );
Console.ReadLine();
}
///// <summary>
///// このコンピューターのローカル IP アドレスを返します。
///// </summary>
///// <returns></returns>
//IPAddress getLocalAddress() {
// IPHostEntry host = Dns.GetHostEntry( Dns.GetHostName() );
// foreach ( IPAddress address in host.AddressList ) {
// if ( address.AddressFamily == AddressFamily.InterNetwork )
// return address;
// }
// return host.AddressList[0];
//}
/// <summary>
///
/// </summary>
/// <param name="args"></param>
static void Main(string[] args) {
StartupAnswerGuestSample progn = new StartupAnswerGuestSample();
progn.run( args );
}
/// <summary>
///
/// </summary>
private static readonly int LOCAL_PORT = 52293;
/// <summary>
///
/// </summary>
private static readonly int RECEIVE_LOOP_MAX = 100;
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using spaghetti.util;
using groan.util;
namespace sample.startupnotify.inqiry {
/// <summary>
///
/// </summary>
class StartupInqiryHostSample {
/// <summary>
///
/// </summary>
void multicastInqiry() {
// 送信先のポートです。
int listen_port = LOCAL_PORT + 1;
/*
* マルチキャストで、グループにパケットを送信し、
* グループに所属しているパソコンが起動しているかどうかを調べます。
*/
UdpClient multicast_client = new UdpClient( LOCAL_PORT, AddressFamily.InterNetwork );
IPAddress group_address = IPAddress.Parse( "239.0.0.0" );
IPEndPoint group_listen_point = new IPEndPoint( group_address, listen_port );
/*
* グループに所属しているパソコンが起動しているかどうかを調べるために、
* マルチキャストでパケットを送信します。
*/
RequestPacket request = new RequestPacket( "inqiry" );
try {
// client をマルチキャストグループに参加させます。
multicast_client.JoinMulticastGroup( group_address, 50 );
Console.WriteLine( "joined a multicast group." );
multicast_client.Connect( group_listen_point );
Console.WriteLine( "connected to {0}.", group_listen_point );
string send_text = request.toXMLString();
byte[] bytes_to_send = Encoding.UTF8.GetBytes( send_text );
Console.Write( "send: " );
multicast_client.Send( bytes_to_send, bytes_to_send.Length );
Console.WriteLine( send_text );
Console.WriteLine( "{0} byte sent.", bytes_to_send.Length );
} finally {
// client をマルチキャストグループから脱退させます。
multicast_client.DropMulticastGroup( group_address );
Console.WriteLine( "leave a multicast group." );
multicast_client.Close();
Console.WriteLine( "closed UDP multicast connection." );
}
}
/// <summary>
///
/// </summary>
/// <param name="param"></param>
void acceptPart(object param) {
int hash = Thread.CurrentThread.GetHashCode();
Console.WriteLine( "=== entering acceptPart {0:x} ===", hash );
TcpListener listener = param as TcpListener;
// ループカウンタ。
int loop_count = 0;
// 非同期情報。
IAsyncResult accept_done = null;
// TCP クライアント。
TcpClient client = null;
// 受信用スレッド。
Thread receive_part_thread = new Thread( receivePart );
// 待機時間。
TimeSpan waiting_time = TimeSpan.FromMilliseconds( 100 );
try {
accept_done = listener.BeginAcceptTcpClient( null, null );
/*
* 受信要求待機ループです。
*/
while ( true ) {
// ペンドってるかどうか。
bool is_pending = listener.Pending();
if ( is_pending )
Console.WriteLine( "thread({0:x}): is pending.", hash );
else
Console.WriteLine( "thread({0:x}): no pending state.", hash );
if ( loop_count > MAX_LOOP ) {
/*
* タイムアウトしました。
* 指定された時間までにシグナルを捕捉できませんでした。
*/
Console.WriteLine( "thread({0:x}): timed out waiting for connection requests.", hash );
this.request_timeouted_.Set();
Console.WriteLine( "=== exiting acceptPart {0:x} ===", hash );
return;
}
// WaitHandle の waitOne メソッドで接続要求を少しだけ待機します。
if ( accept_done.AsyncWaitHandle.WaitOne( waiting_time ) ) {
/*
* シグナルを捕捉したので、待機ループを終了します。
*/
if ( listener.Server.IsBound ) {
/*
* 例外が投げられるのは、この関数内で Start/Stop を行っていたからだった。
* 別のスレッドで Stop メソッドが呼ばれると、ここの EndAcceptTcpClient メソッドでは
* ソケットが閉じられているため、Oops! な事態が起きてしまう…んだと思う。
*/
client = listener.EndAcceptTcpClient( accept_done );
Console.WriteLine( "accept connections." );
IPEndPoint remote_point = (IPEndPoint)client.Client.RemoteEndPoint;
Console.WriteLine( "connection has been requested from {0}.", remote_point );
this.addresses_.Add( remote_point.Address );
loop_count = 0;
receive_part_thread.Start( client );
/*
* 受信完了を待機します。
*/
while ( !receive_part_thread.Join( waiting_time ) ) {
/*
* タイムアウトしました。
*/
if ( loop_count >= MAX_LOOP ) {
//Console.WriteLine();
Console.WriteLine( "{0:x}: listening timed out.", hash );
this.request_timeouted_.Set();
break;
}
++loop_count;
}
} else
this.request_timeouted_.Set();
break;
}
++loop_count;
}
} finally {
loop_count = 0;
}
if ( client != null ) {
Console.WriteLine( "close the client." );
client.Close();
}
Console.WriteLine( "=== exiting acceptPart {0:x} ===", hash );
}
/// <summary>
///
/// </summary>
/// <param name="param"></param>
void receivePart(object param) {
Console.WriteLine( "=== entering receivePart ===" );
TcpClient client = (TcpClient)param;
NetworkStream stream = null;
// ループカウンタ。
int loop_count = 0;
// 待機時間。
TimeSpan waiting_time = TimeSpan.FromMilliseconds( 100 );
// 読み込まれたバイト数。
int amount_of_bytes_read = 0;
// 読み込みに使われるバイト配列。
byte[] byte_array_for_reading = new byte[8096];
// バイト配列をエンコードした文字列。
string received_text = string.Empty;
try {
// ストリームを取得します。
stream = client.GetStream();
if ( stream.DataAvailable ) {
/*
* 非同期読み取りを行います。
*/
IAsyncResult read_done = stream.BeginRead( byte_array_for_reading,
0,
byte_array_for_reading.Length,
null,
null );
/*
* 受信待機ループです。
*/
while ( true ) {
// WaitHandle の waitOne メソッドで受信終了を少しだけ待機します。
if ( read_done.AsyncWaitHandle.WaitOne( waiting_time ) ) {
/*
* シグナルを捕捉したので待機ループを終了します。1
*/
amount_of_bytes_read = stream.EndRead( read_done );
received_text = Encoding.UTF8.GetString( byte_array_for_reading,
0,
amount_of_bytes_read );
Console.WriteLine( "received {0} bytes", amount_of_bytes_read );
Console.WriteLine( "read: {0}", received_text );
break;
} else {
/*
* タイムアウトしました。
* 指定された時間までにシグナルを捕捉できませんでした。
*/
if ( loop_count >= MAX_LOOP ) {
Console.WriteLine( "timed out waiting at reception." );
break;
}
}
++loop_count;
}
} else
Console.WriteLine( "there is no data to read." );
} finally {
if ( stream != null ) {
stream.Close();
Console.WriteLine( "stream close." );
}
}
Console.WriteLine( "=== exiting receivePart ===" );
}
///// <summary>
///// このコンピューターのローカル IP アドレスを返します。
///// </summary>
///// <returns></returns>
//IPAddress getLocalAddress() {
// IPHostEntry host = Dns.GetHostEntry( Dns.GetHostName() );
// foreach ( IPAddress address in host.AddressList ) {
// if ( address.AddressFamily == AddressFamily.InterNetwork )
// return address;
// }
// return host.AddressList[0];
//}
/// <summary>
///
/// </summary>
void run() {
multicastInqiry();
TimeSpan waiting_time = TimeSpan.FromMilliseconds( 100 );
TcpListener listener = new TcpListener( IPAddress.Any, LOCAL_PORT );
// スレッドキュー。
Queue<Thread> thread_queue = new Queue<Thread>( MAXLENGTH_THREAD_QUEUE );
Console.WriteLine( "start the TCP communication." );
Thread.Sleep( 2000 );
Console.WriteLine( "listen start." );
// start() を呼び出すまではソケットが作成されない。
listener.Start();
Console.WriteLine();
try {
/*
* 一つ一つの送信をスレッドにスレッドに割り振ります。
*/
do {
// このループで走るだろうスレッド。
Thread that = null;
/*
* タイムアウト・シグナルを捕捉しようとします。
*/
if ( this.request_timeouted_.WaitOne( waiting_time ) ) {
Console.WriteLine( "sorry, no connection request." );
break;
}
/*
* スレッドを作成、開始し、キューに追加します。
*/
if ( thread_queue.Count <= MAXLENGTH_THREAD_QUEUE ) {
that = new Thread( acceptPart );
that.Start( listener );
thread_queue.Enqueue( that );
} else
Thread.Sleep( waiting_time );
/*
* 既に止まり終わっているスレッドを棄てます。
*/
if ( thread_queue.Count > 0 ) {
Thread peek_thread = thread_queue.Peek();
if ( peek_thread.ThreadState == ThreadState.Stopped ) {
peek_thread = thread_queue.Dequeue();
Console.WriteLine( "dequeue a thread({0:x}).", peek_thread.GetHashCode() );
peek_thread = null;
}
}
} while ( true );
} finally {
Console.WriteLine( "stop the TCP communication." );
Console.WriteLine();
Console.WriteLine( "thread is accumulated in the queue {0}.", thread_queue.Count );
/*
* キューに溜まった全てのスレッドが終了するまで待機します。
*/
while ( thread_queue.Count > 0 ) {
Thread that = thread_queue.Dequeue();
Console.WriteLine( "this thread({0:x}) is {1}.", that.GetHashCode(), that.ThreadState );
switch ( that.ThreadState ) {
case ThreadState.Running:
Console.WriteLine( "this thread({0:x}) calls the join method ...", that.GetHashCode() );
that.Join();
break;
case ThreadState.WaitSleepJoin:
/* !!! fall through !!! */
goto case ThreadState.Aborted;
case ThreadState.Aborted:
Console.WriteLine( "lay about 100 milliseconds the current thread ..." );
Thread.Sleep( 100 );
break;
}
Thread.Sleep( 100 );
}
Console.WriteLine();
Console.WriteLine( "listen stop." );
// stop() を呼び出すとソケットが閉じられる。
listener.Stop();
Console.WriteLine();
}
/*
* 返ってきた IP アドレスを表示します。
*/
if ( addresses_.Count > 0 ) {
Console.WriteLine( "there was a response from {0} places:", addresses_.Count );
foreach ( IPAddress address in addresses_ ) {
Console.WriteLine( address );
}
Console.WriteLine();
} else
Console.WriteLine( "there was no response." );
Console.Write( "press enter to exit: " );
Console.ReadLine();
}
/// <summary>
///
/// </summary>
static void Main() {
StartupInqiryHostSample progn = new StartupInqiryHostSample();
progn.run();
}
/// <summary>
/// 受信した IP アドレスのリスト。
/// </summary>
List<IPAddress> addresses_ = new List<IPAddress>();
/// <summary>
/// 接続要求がタイムアウトしたことを示すシグナル。
/// </summary>
ManualResetEvent request_timeouted_ = new ManualResetEvent( false );
/// <summary>
/// ローカルポート。
/// </summary>
static readonly int LOCAL_PORT = 52292;
/// <summary>
/// スレッドキューの最大長。
/// </summary>
static readonly int MAXLENGTH_THREAD_QUEUE = 10;
/// <summary>
/// 待機ループの最大回数。
/// </summary>
static readonly int MAX_LOOP = 3;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment