今更ながらs.h.log: SocketでC#とProce55ingの通信の続き。学部の頃に徳田先生のネットワークプログラミングの授業で習ったような気がする事を勉強した。
実はTcpClient、TcpListener、Threadまわりを理解してこれを作るのに2ヶ月ぐらいかかった。
Archive(SrouceCode, exe / VisualStudio2005 C#2.0)
3つサンプルを作った。作った順に
1.SocketClient
普通にクライアント。指定したIPのportに接続する。テキストの送受信ができるウィンドウ付き。文字コードはUTF-8
2.SocketServer
普通のソケットサーバー。これ作ったときは、同じPortで複数のclientと接続できる事を知らなかった。SocketClientと1対1で対応する。
3.SocketBridge
SocketServerを改造して、複数clientとセッションをはれる様にした。コレはFlashのAS3から使えるようになったSocketにlistenメソッドが無いので、FlashとFlashを直接通信させる為のオスメス変換的ツールを目指して作った。(FlashMediaServer使えば良いんだけど)
clientから受信したデータを他の全てのclientに転送する様にしたので、ブリッジというよりハブかもしれない。
SocketServerを80番でlistenさせておいて、ブラウザでlocalhostにアクセスしたら反応した。
Client複数をBridgeに接続してメッセージを配信してもらっているところ
FlashからFlashにSocketBridge経由で動画をバイナリで送って再生してみた
大分勉強になった。
特に一番最後に作ったSocketBridgeはすっきり書けて200行ぐらいでできた。A4で印刷して3枚に収まる。。
FormSocketBridge.cs
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Net;//socket関連
usingSystem.Net.Sockets;
usingSystem.Threading;//thread関連
usingSystem.Collections;namespaceSocketServerBridge
{
publicpartialclassFormSocketBridge:Form
{
privateSystem.Text.Encodingenc=System.Text.Encoding.UTF8;//文字コード
privateThreadthread;
privateBooleanthreadStopper;//スレッド停止フラグ
privateAutoResetEventthreadResetEvent;
privateTcpListenerlistener;
privateArrayListclients;publicFormSocketBridge()
{
InitializeComponent();
clients=newArrayList();
}#regionThread/Socke
///
///tcp,stream,threadの破棄
///
privatevoidconnectEnd()
{
if(thread==null)return;threadStopper=true;//スレッド終了フラグ
threadResetEvent.WaitOne();//スレッド終了待ち
thread=null;//破棄
listener.Stop();
for(inti=0;i
{
try
{
((TcpClient)clients[i]).Close();
}
catch(Exceptionex)
{
debug(ex.Message);
}
}
}///
///データ受信スレッド
///
privatevoidrecvThreadStart()
{
byte[]recvBytes;
intrecvSize=0;
threadStopper=false;
while(!threadStopper)
{
if(listener.Pending())//接続待ちがある時
{
TcpClienttcp=listener.AcceptTcpClient();
clients.Add(tcp);
trace(“Connected!”);
trace(“接続数:”+clients.Count);
}
else
{
for(inti=0;i
{
TcpClientclient=(TcpClient)clients[i];
if(!client.Connected)
{
clients.Remove(client);
trace(“DisConnected”);
trace(“接続数:”+clients.Count);
}
else
{
NetworkStreamns=client.GetStream();
if(ns.DataAvailable)//受信データがある時
{
recvBytes=newbyte[3750];
try
{
recvSize=ns.Read(recvBytes,0,recvBytes.Length);
}
catch(Exceptionex)
{
debug(ex.Message);
}
debug(“受信データ長:”+recvSize);
stringrecvMsg=enc.GetString(recvBytes);
debug(“受信データ:”+recvMsg);ArrayListclients2=newArrayList();
for(intj=0;j
{
if(i!=j)clients2.Add(clients[j]);//送ってきた奴には送り返さない
}
broadcastToClients(recvBytes,clients2);
}
}
}
}
Thread.Sleep(10);
}
threadResetEvent.Set();//スレッド終了をWaitOne()に通知
}privatevoidbroadcastToClients(byte[]bytes,ArrayListclients)
{
for(inti=0;i
{
TcpClienttcp=(TcpClient)clients[i];
NetworkStreamns=tcp.GetStream();
try
{
ns.Write(bytes,0,bytes.Length);
}
catch(Exceptionex)
{
debug(ex.Message);
}
}
}#endregion
#regionUIEvent
privatevoidbuttonListen_Click(objectsender,EventArgse)
{
if(thread==null)
{
threadResetEvent=newAutoResetEvent(false);
//listen開始
listener=newTcpListener(IPAddress.Any,int.Parse(textBoxPort.Text));
listener.Start();
trace(“Listen!”);
buttonListen.Text=”DisConnect?”;
textBoxPort.Enabled=false;
thread=newThread(recvThreadStart);
thread.Start();//接続待ち
}
else
{
//listen,threadを止めてtcpsocketを閉じる
connectEnd();
buttonListen.Text=”Connect!”;
textBoxPort.Enabled=true;
trace(“DisConnected”);
}
}privatevoidFormSocketBridge_FormClosed(objectsender,FormClosedEventArgse)
{
connectEnd();
}
#endregion#regionUIMethod
///
///テキストボックスに表示する
///
///
publicvoidtrace(Stringmessage)
{
Console.WriteLine(message);
if(checkBoxDisplayLog.Checked)
{
try
{
this.Invoke((MethodInvoker)delegate()
{
textBoxLog.Text=textBoxLog.Text+”¥r¥n”+message;
});
}
catch(Exceptionex)
{
Console.WriteLine(ex.Message);
}
}
}publicvoiddebug(Stringmessage)
{
#ifDEBUG
trace(message);
#endif
}
#endregion}
}