2016年1月26日火曜日
非同期ソケット通信サーバー側
試行錯誤中のゴミが大量混入ver
class SocketServer
{
//ホスト名からIPアドレスを取得する時は、次のようにする
//string host = "localhost";
//System.Net.IPAddress ipAdd =
// System.Net.Dns.GetHostEntry(host).AddressList[0];
//.NET Framework 1.1以前では、以下のようにする
//System.Net.IPAddress ipAdd =
// System.Net.Dns.Resolve(host).AddressList[0];
private System.Net.Sockets.TcpClient objSckClient;
System.Net.Sockets.NetworkStream SendNS;
private System.Net.Sockets.TcpListener objSckServer;
private System.Threading.Thread ListeningCallbackThread;
private volatile bool SLTAlive;
private volatile bool SendAlive;
public SocketServer()
{
objSckClient = new System.Net.Sockets.TcpClient();
SLTAlive = false;
SendAlive = false;
//---------------------
InvokeMethod = new InvokeMethodDelegate(BeginInvokeTypeMethod);
Caller = new CommunicationCallbackDelegate(CommunicationCallback);
}
public void Recieve_Close()
{
if (SLTAlive)
{
SLTAlive = false;
objSckServer.Stop();
ListeningCallbackThread = null;
}
}
public void Recieve_Stop()
{
if (objSckServer != null)
{
objSckServer.Stop();
}
SLTAlive = false;
Console.WriteLine("サーバー正常終了");
}
public void Recieve_CreateThread()
{
SLTAlive = true;
ListeningCallbackThread = new System.Threading.Thread(ListeningCallback);
ListeningCallbackThread.Start();
}
private void ListeningCallback()
{
objSckServer = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 12323);
objSckServer.Start();
Console.WriteLine("サーバー開始");
try
{
int cnt = 0;
while (SLTAlive)
{
cnt++;
Console.WriteLine("1, " + cnt);
if (objSckServer.Pending())
{
Console.WriteLine("2, " + cnt);
System.Net.Sockets.TcpClient ClientSocket = objSckServer.AcceptTcpClient();
Console.WriteLine("connected : " + ((System.Net.IPEndPoint)ClientSocket.Client.RemoteEndPoint).Address + ", " + ((System.Net.IPEndPoint)ClientSocket.Client.RemoteEndPoint).Port);
System.Net.Sockets.NetworkStream stream = ClientSocket.GetStream();
byte[] RecieveData = new Byte[2000];
int DataLength = stream.Read(RecieveData, 0, RecieveData.Length);
string str = System.Text.Encoding.Unicode.GetString(RecieveData, 0, DataLength);
Console.WriteLine("受け取り手:" + str);
byte[] SendBuffer = System.Text.Encoding.Unicode.GetBytes("サーバーメッセージ");
stream.Write(SendBuffer, 0, SendBuffer.Length);
stream.Flush();
ClientSocket.Close();
}
System.Threading.Thread.Sleep(100);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public void Send_Connect()
{
objSckClient.Connect("127.0.0.1", 12323);
Console.WriteLine("サーバー({0}:{1})と接続しました({2}:{3})。", ((System.Net.IPEndPoint)objSckClient.Client.RemoteEndPoint).Address, ((System.Net.IPEndPoint)objSckClient.Client.RemoteEndPoint).Port, ((System.Net.IPEndPoint)objSckClient.Client.LocalEndPoint).Address, ((System.Net.IPEndPoint)objSckClient.Client.LocalEndPoint).Port);
SendNS = objSckClient.GetStream();
SendNS.ReadTimeout = 10000; //10sec
SendNS.WriteTimeout = 10000; //*1ms
SendAlive = true;
}
public void Send_Execute()
{
if (SendAlive)
{
String SendMessage = "メッセージ送信";
byte[] sendBytes = System.Text.Encoding.Unicode.GetBytes(SendMessage + "\n");
SendNS.Write(sendBytes, 0, sendBytes.Length);
Console.WriteLine("送り手:メッセージ送信済");
}
}
public void Send_Close()
{
if (SendAlive)
{
SendNS.Close();
objSckClient.Close();
Console.WriteLine("クライアントとの接続終了");
}
}
//--------------------------------------------------------------------------------------------------------------
//メンバ変数
// 送受信電文処理スレッド呼び出し用オブジェクト
private CommunicationCallbackDelegate Caller;
// 送受信電文処理メソッド用デリゲート
delegate ProcessingResultOfCommunication CommunicationCallbackDelegate(System.Net.Sockets.TcpListener listener);
// 待機中のスレッドを管理するオブジェクト
public static System.Threading.ManualResetEvent AllDone = new System.Threading.ManualResetEvent(false);
//----------------------------------------------------------------------------------------------------------------
public class ProcessingResultOfCommunication
{
public string ReceivedData; // 受信データ
public string Reply; // 返信(送信データ)
}
//----------------------------------------------------------------------------------------------------------------
public void Recieve_Start2()
{
if (!SLTAlive) // まだ接続待ちスレッドを生成していない場合
{
// リスナー(接続要求受け入れ待機)を生成
objSckServer = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Parse("127.0.0.1"), 12323);
// *** server = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 9000);
// 接続要求受け入れ開始
objSckServer.Start();
// 接続待ち用スレッドを作成
ListeningCallbackThread = new System.Threading.Thread(ListeningCallback2);
// 接続待ち用スレッドを開始
ListeningCallbackThread.Start();
// スレッド終了指示フラグを未終了に設定
SLTAlive = true;
}
}
// ************************************
// 接続待ちスレッド用メソッド
// --- クライアントからの受信受け付けを行なうメソッドです。なお、受信受
// け付けを常に行なうため、無限ループで受け付け処理を行っています。
// 無限ループは、処理を占有して、本サーバープログラム自体の動作に影
// 響しますので、本メソッドは、スレッドとして起動します。
// ************************************
private void ListeningCallback2()
{
// label1.Text = "サーバー開始";
Console.WriteLine("サーバー開始");
try
{
// 受信の受付を行なうための無限ループ
while (SLTAlive) // スレッド終了指示フラグでの終了指示がある場合はループ終了
{
// 受信接続キュー内で、接続待ちがあるか判断
if (objSckServer.Pending() == true)
{
// AllDoneを非シグナル状態にする
// すなわち、スレッドの実行指示の状態をリセットして戻す。
AllDone.Reset();
// スレッドを起動し、送受信電文処理スレッド用メソッドを実行します。
InvokeMethod();
// AllDoneがシグナル状態になるまでスレッドをブロック。
// すなわち、送受信電文処理用スレッドから、実行開始の指示が出るまで待機する。
AllDone.WaitOne();
}
// 短時間だけ待機
System.Threading.Thread.Sleep(100);
}
}
catch (Exception ex)
{
Console.WriteLine("サーバー終了\n" + ex);
}
}
//----------------------------------------------------------------------------------------------------------------
//========================
// 電文処理スレッド起動メソッド用デリゲート
//========================
delegate void InvokeMethodDelegate();
private InvokeMethodDelegate InvokeMethod;
//----------------------------------------------------------------------------------------------------------------
// ************************************
// 送受信電文処理スレッド用メソッド
// --- 受信された電文に対して、具体的な処理を行なうメソッドです。このサ
// ンプルでは、受信電文をテキストボックスに表示し、また、クライアン
// トへ返信を返す処理としています。
// なお、本メソッド(電文処理部)は、複数のクライアントからの接続に対
// 応しています。すなわち、受信があるたびにスレッドが起動し、本メソ
// ッドが実行されます。
// 第1引数: クライアントからの受信接続要求を処理するリスナー
// 戻り値: 処理結果
// ************************************
public ProcessingResultOfCommunication CommunicationCallback(System.Net.Sockets.TcpListener listener)
{
// AllDoneをシグナル状態にする。
// すなわち、接続待ちスレッドのロックを解除して、接続待ちスレッドの実行再開の許可をする。
AllDone.Set();
// 処理結果格納用クラスの生成
ProcessingResultOfCommunication ResultData = new ProcessingResultOfCommunication();
if (SLTAlive) // 接続待ちスレッドが作成されていて使える場合
{
try
{
// クライアントからの接続を受け付ける
System.Net.Sockets.TcpClient ClientSocket = listener.AcceptTcpClient(); // TCPクライアント
// 通信ストリームの取得
System.Net.Sockets.NetworkStream stream = ClientSocket.GetStream();
//============
// クライアントからの電文の受信
byte[] ReceiveData = new byte[2000];
int DataLength = stream.Read(ReceiveData, 0, ReceiveData.Length); // 電文の列長
string str = System.Text.Encoding.Unicode.GetString(ReceiveData, 0, DataLength);
//============
// 処理結果格納用クラスに本メソッドの処理結果を格納
// 受信データーを処理結果格納用クラスに設定
ResultData.ReceivedData = str;
// 返信データーの作成
ResultData.Reply = "通信データー<< " + str + ">>を受け取りました。";
//============
// サーバーで処理時間のかかる処理が行なわれる場合を、仮に実験したい
// 場合は、下記の時間待機のメソッドを実行させて下さい。
// *** System.Threading.Thread.Sleep(30000);
//============
// 返信電文をクライアントへ送信
byte[] SendBuffer = System.Text.Encoding.Unicode.GetBytes(ResultData.Reply);
stream.Write(SendBuffer, 0, SendBuffer.Length);
stream.Flush(); // フラッシュ(強制書き出し)
// 通信ストリームをクローズ
stream.Close();
// TCPクライアントをクローズ
ClientSocket.Close();
}
catch (Exception ex)
{
}
}
return ResultData;
}
//------------------------------------------------------------------------------------------
//========================
// ノンブロッキング通信指定時に使われるメソッド
//========================
//========================
// ノンブロッキング通信指定時の電文処理スレッド起動用メソッド
private void BeginInvokeTypeMethod()
{
// ワーカースレッドでの処理終了時に起動するコールバックメソッドを指定
AsyncCallback asc = new AsyncCallback(ReturnCallback);
// スレッドを起動し、送受信電文処理スレッド用メソッドを実行します。
IAsyncResult AsyRes = Caller.BeginInvoke(objSckServer, asc, null);
//IAsyncResult AsyRes = Caller.BeginInvoke(ServerSocket, asc, new object[] { ServerSocket });
}
//========================
// スレッド完了時起動のコールバックメソッド
// BeginInvokeでの呼び出し(非同期呼び出し)で起動されるスレッドにおいて、
// その処理が完了した時に、呼び出し元に呼び出されるメソッドです。
// よって、ワーカースレッド(BeginInvokeで呼び出されるスレッド)での処理
// 結果に関する処理等をここに定義すると便利です。
// 第1引数: 非同期デリゲートでの非同期操作の結果(をカプセル化した物)
public void ReturnCallback(IAsyncResult AsyRes)
{
// 結果を取り出すための非同期結果のキャスト。
System.Runtime.Remoting.Messaging.AsyncResult aResult = (System.Runtime.Remoting.Messaging.AsyncResult)AsyRes;
// 非同期の呼び出しが行われたデリゲート オブジェクトを取得。
CommunicationCallbackDelegate dele = (CommunicationCallbackDelegate)aResult.AsyncDelegate;
// デリゲートの完了処理を実行。及びワーカースレッドでの処理結果の受け取り。
ProcessingResultOfCommunication ResultData = dele.EndInvoke(AsyRes);
// 受信データを表示
//textBox1.Text += ResultData.ReceivedData + "\r\n";
Console.WriteLine(ResultData.ReceivedData);
}
}
【参考】http://note.chiebukuro.yahoo.co.jp/detail/n26284
ソケット通信クライアント側
class SocketClient2
{
public SocketClient2() { }
public void mai(String ipOrHost, int port, String sendMsg)
{
if (sendMsg == null || sendMsg.Length == 0)
{
return;
}
//TcpClientを作成し、サーバーと接続する
System.Net.Sockets.TcpClient tcp =
new System.Net.Sockets.TcpClient(ipOrHost, port);
Console.WriteLine("サーバー({0}:{1})と接続しました({2}:{3})。",
((System.Net.IPEndPoint)tcp.Client.RemoteEndPoint).Address,
((System.Net.IPEndPoint)tcp.Client.RemoteEndPoint).Port,
((System.Net.IPEndPoint)tcp.Client.LocalEndPoint).Address,
((System.Net.IPEndPoint)tcp.Client.LocalEndPoint).Port);
//NetworkStreamを取得する
System.Net.Sockets.NetworkStream ns = tcp.GetStream();
//読み取り、書き込みのタイムアウトを10秒にする
//デフォルトはInfiniteで、タイムアウトしない
//(.NET Framework 2.0以上が必要)
ns.ReadTimeout = 10000;
ns.WriteTimeout = 10000;
//サーバーにデータを送信する
//文字列をByte型配列に変換
//System.Text.Encoding enc = System.Text.Encoding.UTF8;
System.Text.Encoding enc = System.Text.Encoding.Unicode;
byte[] sendBytes = enc.GetBytes(sendMsg + '\n');
//データを送信する
ns.Write(sendBytes, 0, sendBytes.Length);
Console.WriteLine(sendMsg);
//サーバーから送られたデータを受信する
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] resBytes = new byte[256];
int resSize = 0;
do
{
//データの一部を受信する
resSize = ns.Read(resBytes, 0, resBytes.Length);
//Readが0を返した時はサーバーが切断したと判断
if (resSize == 0)
{
Console.WriteLine("サーバーが切断しました。");
break;
}
//受信したデータを蓄積する
ms.Write(resBytes, 0, resSize);
//まだ読み取れるデータがあるか、データの最後が\nでない時は、
// 受信を続ける
} while (ns.DataAvailable || resBytes[resSize - 1] != '\n');
//受信したデータを文字列に変換
string resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length);
ms.Close();
//末尾の\nを削除
resMsg = resMsg.TrimEnd('\n');
Console.WriteLine(resMsg);
//閉じる
ns.Close();
tcp.Close();
}
}
【参考】http://dobon.net/vb/dotnet/internet/tcpclientserver.html
登録:
投稿 (Atom)