Top / DCOM でチャット / 1. チャットサーバー

チャットサーバーに必要な機能

チャットサーバーには、以下の機能が必要です。

ユーザ管理機能
セション管理機能

それでは、個々の機能について、どのように実現しているか、解説していきます。

ここで、注意しておくべきことがあります。ActiveX.DLL は、インプロセスで動作するため、多数のユーザが一つのプログラムに接続するといった用途には不向きです。ActiveX.EXE にしましょう。

Visual Basic を立ち上げ、ActiveX.EXE を選択します。

init.gif

ユーザ管理機能

接続してきたユーザは、コレクションに積み上げることにします。

切断されたら、コレクションから削除しなくてはなりません。
コレクションから、削除するためには、ユニークなキーが必要です。
そこで、ユニークなキーを作成するために、自動採番という技法を使います。

つまり、カウンタを用意し、ユーザが接続するたびに、それをカウントアップし、ユーザに割り当てるといった手法です。

これらの機能を満たすために、サンプルプログラムには、以下の変数を設けています。(DCOMChat.bas)

Public gcolUser As Collection
Public glngUser As Long

変数 gcolUser には、ユーザを積み上げます。 glngUser は、カウンタです。

CUser

コレクションに積み上げるための、クラスを作成します。クラス名は、CUser とします。
機能については、以下の3点あればよいでしょう。

名前機能
Name プロパティユーザ名を保持
Hear イベント発言を聞く
Talk メソッド発言する

Name プロパティ

プロパティに代入したとき、同じユーザ名をもつ人がいないかどうか、チェックしたいので、Property プロシージャを使って、プロパティを作成します。

Dim mName As String

Public Property Let Name(ByVal New_Name As String)
    Dim objuser As CUser
    For Each objuser In gcolUser
        If objuser.Name = New_Name Then
            Err.Raise 1581, ,"ユーザ名が重複しています。"
            Exit Property
        End If
    Next
    mName = New_Name
End Property

Public Property Get Name() As String
    Name = mName
End Property

Hear イベント

「発言を聞く」という動作に関して言えば、イベントであると考えられます。 だれが、どんな発言をしたかという情報が必要なので、以下のようにコーディングします。

Public Event Hear(ByVal UserName As String, ByVal Message As String)

ここで、UserName は、だれが、に相当し、Message は、発言に相当します。

だれかが発言したら、すべてのユーザがそれを聞くことになりますから、発言というメソッドから、すべてのユーザに対して、Hear イベントを呼び出すようなしくみにしなくてはなりません。

そのためには、Hear イベントを起こすための、メソッド RaiseHear を作成します。
これは、外部に公開するべきメソッドではないので、Friend キーワードを使いましょう。

Friend Sub RaiseHear(ByVal UserName, ByVal Message As String)
    RaiseEvent Hear(UserName, Message)
End Sub

Talk メソッド

発言するというメソッド Talk を作成します。
どんな発言をしたかという情報が必要なので、次のようにコーディングします。

Public Sub Talk(ByVal Message As String)
    Dim objUser As CUser
    For Each objUser In gcolUser
        objUser.RaiseHear Me.Name, Message
    Next
End Sub

gcolUser コレクションから、すべてのユーザを列挙し、Hear イベントを発生させています。
発言したユーザは、自分自身なので、Me.Name を発言ユーザとしています。

セション管理機能

セション管理機能(CSession.cls)は、各ユーザの接続を管理します。

すなわち、

セションの接続 接続されたら、ユーザオブジェクトを作成し、コレクションに積み上げる。

セションの切断 切断されたら、ユーザオブジェクトをコレクションから削除し、ユーザを廃棄する。

これらの機能に加え、

ユーザオブジェクトの機能をインプリメントする。

こともしてみます。

CSession.cls

セションの接続

セション接続では、

ユーザオブジェクトを作成
ユーザオブジェクトをコレクションに追加

といった、機能を実現します。

セションが接続(CSessionオブジェクトが作成)されたとき、Class_Initialize イベントが発生します。

'コレクションから、オブジェクトを特定するためのキーを保存する変数です。
Dim mUserKey As String
'ユーザオブジェクトのイベントを受け取ります。
Private WithEvents mUser As CUser

Private Sub Class_Initialize()
    'コレクションオブジェクトがまだ作成されていなければ、作成します。
    If gcolUser Is Nothing Then
       Set gcolUser = New Collection
    End If
    'ユーザオブジェクトを作成します。
    Set mUser = New CUser
    'コレクションに積み上げます。(自動採番処理)
    glngUser = glngUser + 1
    mUserKey = "K" & glngUser
    gcolUser.Add mUser, mUserKey
End Sub

セションの切断

セション切断では、

ユーザオブジェクトをコレクションから削除
ユーザオブジェクトを破棄

といった、機能を実現します。

セションが切断(CSessionオブジェクトが破棄)されたとき、Class_Terminate イベントが発生します。

Private Sub Class_Terminate()
    '保存しておいたキーで、コレクションから削除
    gcolUser.Remove mUserKey
    'ユーザオブジェクトを破棄
    Set mUser = Nothing
End Sub

ユーザオブジェクトのインプリメント

ユーザオブジェクトには、以下の3つの公開された機能がありました。

Name プロパティ
Talk メソッド
Hear イベント

これらの機能をインプリメントします。

Name プロパティは、UserName というプロパティでインプリメントします。

Public Property Get UserName() As String
    UserName = mUser.Name
End Property

Public Property Let UserName(ByVal New_UserName As String)
    mUser.Name = New_UserName
End Property

Talk メソッドは、Talk というメソッドで、インプリメントします。

Public Sub Talk(ByVal Message As String)
    mUser.Talk Message
End Sub

Hear イベントは、Hear イベントで、インプリメントします。

Public Event Hear(ByVal UserName As String, ByVal Message As String)
Private Sub mUser_Hear(ByVal UserName As String, ByVal Message As String)
    RaiseEvent Hear(UserName, Message)
End Sub

ちょっとした機能

接続した、すべてのユーザ名が解ると便利だとは思いませんか? 思わない?

便利だったら便利なの!と、いうわけで(爆)、Users という、プロパティで、gcolUser コレクションを公開します。

Public Property Get Users() As Collection
    Set Users = gcolUser
End Property

Instancing プロパティ

ActiveX.EXE のクラスモジュールには、Instancing というプロパティがあります。

inst.gif

これは、外部から、クラスオブジェクトを作成できるかどうかを指定するものです。

簡単に説明すると、

Private外部から、このクラスには、まったくアクセスできません。
PublicNotCreatable外部から、このクラスを参照できますが、新規に作成できません。
MultiUse外部から、このクラスを新規に作成できます。またコンポーネントのインスタンスを共有します。
SingleUse外部から、このクラスを新規に作成できます。コンポーネントのインスタンスを起動します。
GlobalMultiUseMultiUse と同様です。このクラスのメソッドやプロパティは、直接呼び出せます。
GlobalSingleUseSingleUse と同様です。このクラスのメソッドやプロパティは、直接呼び出せます。

CUser クラスについて

ユーザーのプロパティには、アクセスできると便利ですが、接続なしに、勝手に作成されては困りますから、新規作成はできなくしたほうがよいので、PublicNotCreatable が適当でしょう。

CCsession クラスについて

セッションは、使用するアプリケーションから、新規に作成できる必要があります。 また、コンポーネント側のインスタンスを共有しないと、各セッション同志で通信できませんから、MultiUse が適当でしょう。 GlobalMultiUse でも、問題ないのですが、インスタンスを明示しなくても使えてしまうので、 コンポーネントと、関数がごっちゃになってしまいそうで、私は好きじゃありません。(^_^;)

Friend と Public

それぞれのクラスオブジェクトのプロパティ、メソッド、そしてイベントを整理し、公開すべきかどうか整理してみます。

CUserクラス

Nameプロパティ参照のみ
RaiseHear メソッド×
Talk メソッド×
Hear イベント×

CSessionクラス

UserNameプロパティ
Usersプロパティ参照のみ
Talk メソッド
Hearイベント

公開したくないものについては、Friend キーワードを指定することで対処できます。

(例) CUser クラスの Talk メソッド

Friend Sub Talk(ByVal Message As String)
    Dim objUser As CUser
    For Each objUser In gcolUser
        objUser.RaiseHear Me.Name, Message
    Next
End Sub

CUser クラスの Name プロパティに関しては、Property Let を、Friend に、 Property Get を、Public にします。 これで、参照のみ公開することができました。

イベントを非公開にする

イベントは、通常、Public になります。しかも、Friend キーワードが指定できません。 ですから、オブジェクトを公開してしまうと、かならず、公開されてしまいます。

公開はされますが、オブジェクトブラウザで、非表示にすることはできます。

クラスモジュールを表示して、開発環境のメニューから、「ツール」→「プロシージャ属性」をクリックすると次のような画面になります。

proc.gif

名前に、Hear を選択し、「詳細」ボタンを押すと、次のようになります。

hear.gif

コレクションを参照のみにする

Users プロパティは、コレクションです。

機能に不足はないのですが、Collection オブジェクトを、そのまま公開しているので、 Add メソッドや、Remove メソッドが使えてしまいます。

そこで、独自のコレクションクラス(CCollection.cls)を作成して、それを公開することにします。

もちろん、Instancing プロパティは、PublicNotCreatable ですね。

サポートすべき機能

機能名対処方法
Add メソッドFriend キーワードを使って、メソッドを作成して、インプリメントします。
RemoveメソッドFriend キーワードを使って、メソッドを作成して、インプリメントします。
Count プロパティPublic Property Get で、インプリメントします。
Item プロパティPublic Property Get で、インプリメントします。このプロパティを既定値としておけば、通常の Collection オブジェクトと同様に使用することができます。
列挙For Each ... In で、列挙するための手順を以下に述べます。

For Each .. In で列挙を可能にする方法

次のようなメソッド、NewEnum を作成します。

Public Function NewEnum() As IUnknown
    Set NewEnum = mobjCol.[_NewEnum]
End Function

「ツール」→「プロシージャの属性」で、以下のように設定します。

newenum.gif

プロシージャIDに、「-4」、「このメンバを非表示にする」をチェックし、「OK」ボタンを押します。

あとは、Collection となっている箇所を、CCollection に変更するだけです。

CChat.bas

Public gcolUser As CCollection

CSession.cls

Public Property Get Users() As CCollection
    Set Users = gcolUser
End Property

サーバーのコンパイル

では、必要なモジュールはすべてそろったので、コンパイルします。

その前に、「プロジェクト」→「CChatのプロパティ」で、「コンポーネント」タグを見てください。

property.gif

上の図は、新規作成したときの状態です。

このままでは、.VBR ファイルが作成されません。

.VBR ファイルには、ActiveX サーバーをリモートコンピュータで実行させるのに必要な Windows レジストリ情報が記録されます。

VBR ファイルを作成するためには、「リモートサーバーファイル」をチェックする必要があります。

「リモートサーバーファイル」をチェックし、「OK」ボタンを押してコンパイルしてください。




トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2009-10-25 (日) 23:56:11 (2852d)