Lesson 22:通信部分を部品化

 今回は、二年ぶりに年末年始をぐっすりと休むことができました。本当は、その間にここの更新作業をやればよかったのですが。年末にちょっと楽しいおもちゃを購入してしまったため、そちらのプログラム開発をやってしまいました。
 そちらのプログラムもまだ完成していないのですが、ここの更新があまりにも開いてしまったので、こちらの作業に戻りたいと思います。

 前回は、受信部分を別スレッド化しましたが、今回は、今までに作成した通信部分をまとめて、クラス化したいと思います。
 今回の通信の目標はメールチェックできるところまでなので、クライアント側の処理さえまとまっていれば十分ですので、クライアント側の機能を中心にクラス化します。
 クラスの名前はVTcpNetworkClientとしておきます。このクラスの機能としては、
とします。最後のアクセプトはサーバ側の機能で、listenで受け取った接続要求を処理するために使用します。

 それではクラスの構成を考えていきます。
 まず考えるのは初期処理と後始末ですが、これは当然コンストラクタとデストラクタで行います。クラス名をVTcpNetworkClientとしたので、コンストラクタはVTcpNetworkClient()、デストラクタは~VTcpNetworkClient()となります。コンストラクタでは諸変数の初期化を行い、デストラクタでは切断作業を行います。 また、今回も受信部分は別スレッドにして、受信データの受け渡しはメッセージを使用しますので、コンストラクタの引数でメッセージの送信先を指定できるようにしておきます。コンストラクタの宣言は、VTcpNetworkClient(BLooper *Owner)となります。
 接続は、ホストのアドレスと使用するポートの指定ができるようにしておき、戻り値として接続したソケットを返すようにしておきます。宣言は、int sock_connect(char *host,int port)となります。
 切断は、特に指定するような内容もないので、void sock_closed(void)とします。
 送信は、送信するデータとそのサイズを指定する必要がありますので、int sock_send(void *data,int32 length)とします。戻り値にはsend関数の戻り値を返すようにします。
 受信部分はvtcp_rec_threadという名前の関数として作成します。スレッド関数ですのでstatic int32 vtcp_rec_thread(void *Dummy)と宣言します。この関数をstaticとするのは、スレッドを作成するspawn_thread関数に関数ポインタを渡す必要があるためです。
 アクセプトは、ソケットを指定する必要があるので、int sock_accept(int s)と宣言します。この関数も戻り値としてソケットを返します。

 ここまでの条件でクラスの宣言を作成すると
//---------------------------------------------------------------------
class VTcpNetworkClient
{
private:
    static int32 vtcp_rec_thread(void *Dummy);
public:
    VTcpNetworkClient(BLooper *Owner);
    ~VTcpNetworkClient(void);
    int sock_connect(char *host,int port);
    int sock_send(void *data,int32 length);
    void sock_closed(void);
    int sock_accept(int s);
};
//---------------------------------------------------------------------
となります。
 次に考えなければいけないのは、クラス内で保持しておく必要のある情報についてでしょう。
 まず思いつくのは、コンストラクタの引数として受け取っているOwnerを保持しておくことでしょう。これはMyOwnerとしておきます。型はOwnerと同じBLooper *です。
 それとTCPで通信を行う以上、絶対に必要になるのはソケットです。これもint nsockとして保存用の変数を宣言しておきます。また、この変数を参照するための手段として、int GetSocket(void)という関数を準備しておきます。
 あとは受信処理のスレッドを特定するために、スレッドのIDとスレッドの名前を保存する必要があります。IDはint32 recthread、名前はchar threadname[32]に保存するようにします。

 このクラスから通知するメッセージは受信情報と切断時の通知ですので、それも定義し、前回作成したRecThreadDataも宣言してヘッダファイルを作成してしまいましょう。ファイル名はvtcpnet.hとしておきます。


/**** ファイル名 : MainWindow.h ****/

#ifndef VTCPNETH
#define VTCPNETH
//---------------------------------------------------------------------
#include <Be.h>
#include <be/net/socket.h>
//---------------------------------------------------------------------
#define MSG_VTCP_CLOSED  'clsd'
#define MSG_VTCP_RECV    'recv'
//---------------------------------------------------------------------
class VTcpNetworkClient
{
private:
    struct RecThreadData
    {
        int sock;
        BLooper *owner;
    };

    int nsock;
    int32 recthread;
    char threadname[32];
    BLooper *MyOwner;
    static int32 vtcp_rec_thread(void *Dummy);
    bool MakeThreadName(char *name,char *des);
public:
    VTcpNetworkClient(BLooper *Owner);
    ~VTcpNetworkClient(void);
    //-----------------------------------------------------------------
    int sock_connect(char *host,int port);
    int sock_send(void *data,int32 length);
    void sock_closed(void);
    int sock_accept(int s);
    int GetSocket(void)
    {
        return nsock;
    };
};
//---------------------------------------------------------------------
#endif

 GetSocket関数はnsock変数の値を返すだけですので、インラインで作成してしまいます。

 次に各関数を作成していきますが、基本的には前回のプログラムのMainWindow.cppで作成した関数を移動して手を加えるだけです。
 まずは、コンストラクタとデストラクタから作成していきます。
 コンストラクタでは、諸変数の初期化を行いますので、nsock、recthread、threadname、MyOwnerに値をセットするだけです。
//---------------------------------------------------------------------
VTcpNetworkClient::VTcpNetworkClient(BLooper *Owner)
{
    MyOwner=Owner;
    
    recthread=-1;
    nsock=-1;
    threadname[0]='\0';
}
//---------------------------------------------------------------------

 デストラクタではソケットをクローズしなかった場合に備えて、sock_closed関数を呼び出します。
//---------------------------------------------------------------------
VTcpNetworkClient::~VTcpNetworkClient(void)
{
    sock_closed();
}
//---------------------------------------------------------------------
 sock_connect関数では、ソケットの作成からサーバへの接続、受信スレッドの作成まで行います。
 基本的な流れは前回と同じですのでが、二点大きく変更している部分があります。
 一点目は、接続先アドレスの指定方法です。今まではinet_addr関数を使用して、"127.0.0.1"といったドットで区切った10進数の文字列をIPアドレスに変換していましたが、このinet_addr関数を使用した方法では"www.asahi-net.or.jp"といったドメイン名を使用することができません。
 そこで、ドメイン名からIPアドレスを取得するために、inet_addr関数が失敗した場合は、gethostbyname関数を使用して、ホストの情報を取得するようにします。gethostbyname関数はドメイン名を指定することで、いくつかのホストの情報を取得することがでますので、その情報からIPアドレス取得するようにします。
 二点目は、スレッドの名前の決定方法です。前回は、ClientRecvThreadといった文字列の後ろにソケットの番号を付加して、それをスレッドの名前として使用していました。ですが、この方法だと、別プロセスで複数のプログラムを起動した際に、同じ名前のスレッドを作成することになってしまいます。その対策として、同じ名前のスレッドが存在するかを確認してからスレッド名を決定するようにします。
 MakeThreadNameという名前で、同じ名前のスレッドが存在しないことを考慮して、指定した文字列の後ろに連番を付加した名前を決定する関数を作成します。
//---------------------------------------------------------------------
bool VTcpNetworkClient::MakeThreadName(char *name,char *des)
{
    char wk[33];
    static int i=0;
    
    for(;i<1024;i++)
    {
        sprintf(wk,"%s%d",name,i);
        if(find_thread(wk)==B_NAME_NOT_FOUND)
        {
            strcpy(des,wk);
            return true;
        }
    }

    return false;
}
//---------------------------------------------------------------------
 同名のスレッドが存在するかを確認するにはfind_thread関数を使用します。スレッドが存在しなければ、find_thread関数はB_NAME_NOT_FOUNDを返します。
 そこで、名前の後ろにつける連番を0から順にインクリメントしていき、find_thread関数がB_NAME_NOT_FOUNDを返した時点で、それをスレッドの名前として返すようにします。

 gethostbyname関数とMakeThreadName関数を組み込むと、sock_connect関数は次のようになります。
//---------------------------------------------------------------------
int VTcpNetworkClient::sock_connect(char *host,int port)
{
    struct sockaddr_in sa;
    int r;

    nsock=socket(AF_INET, SOCK_STREAM, 0);
    sa.sin_family=AF_INET;
    sa.sin_port=htons((short)port);
    sa.sin_addr.s_addr=inet_addr(host);
    if(sa.sin_addr.s_addr==0xFFFFFFFFul)
    {
        hostent *h;
        
        h=gethostbyname(host);
        if(h!=NULL)
            sa.sin_addr.s_addr=*(unsigned int *)h->h_addr;
    }
    memset(sa.sin_zero,0,sizeof(sa.sin_zero));
    r=connect(nsock,(struct sockaddr *)&sa,sizeof(sa));

    if(r!=-1)
    {
        struct RecThreadData rdata;
        
        rdata.sock=nsock;
        rdata.owner=MyOwner;
        if(MakeThreadName("ClientRecvThread",threadname))
        {
            recthread=spawn_thread(vtcp_rec_thread,threadname,
                                   B_NORMAL_PRIORITY,NULL);
            send_data(recthread,63,(void *)&rdata,sizeof(rdata));
            resume_thread(recthread);
        }
        else
        {
            closesocket(nsock);
            nsock=-1; 
        }
    }
    else
    {
        closesocket(nsock);
        nsock=-1; 
    }
    
    return nsock;
}
//---------------------------------------------------------------------

 接続ができたら次は切断です。
 切断で行わなければいけない事は、二点だけです。一点は、ソケットが作成されていたら、それをクローズすること。もう一点は、受信用のスレッドが作成されていたら、それを終了することです。
 ソケットを作成した場合は、nsock変数の値が-1以外になりますので、それをチェックして、-1以外の場合は、closesocket関数でソケットをクローズします。
 スレッドは、threadnameにスレッド名が設定されているか否かと、スレッド名が設定されていれば、そのスレッドが存在するかをチェックして、存在する場合は、そのスレッドをkill_thread関数で終了します。
//---------------------------------------------------------------------
void VTcpNetworkClient::sock_closed(void)
{
    int32 fthread;
        
    if(nsock!=-1)
    {
        closesocket(nsock);
        nsock=-1;
    }

    if(strlen(threadname)>0)
        if((fthread=find_thread(threadname))!=B_NAME_NOT_FOUND) 
        {
            kill_thread(fthread);
            threadname[0]='\0';
        }
}
//---------------------------------------------------------------------
 繰り返して使用することを考慮して、nsockとthreadnameを初期化するのを忘れないでください。

 送信は、ほとんど説明する必要はないですね。
 send関数で送信処理を行い、もし送信処理が失敗したら、ソケットをクローズして、その旨のメッセージ(MSG_VTCP_CLOSED)を親に送信するだけです。
//---------------------------------------------------------------------
int VTcpNetworkClient::sock_send(void *data,int32 length)
{
    int r;
    
    r=send(nsock,data,length,0);
    if(r==-1)
    {
        sock_closed();

        BMessage *sendmsg=new BMessage(MSG_VTCP_CLOSED);
        sendmsg->AddInt32("socket",nsock);
            
        MyOwner->PostMessage(sendmsg);
        delete sendmsg; 
    }
    return r;
}
//---------------------------------------------------------------------

 次は大物の受信処理ですが、前回のスレッド関数とほとんど同じ内容ですので、特に説明はしません。
//---------------------------------------------------------------------
int32 VTcpNetworkClient::vtcp_rec_thread(void *Dummy)
{
    int sock;
    BLooper *Owner;
    struct timeval tv;
    struct fd_set fds;
    BMessage *sendmsg;
    unsigned char buf[1024];
    ssize_t rec;
    RecThreadData rdata;
    int32 sender;
    int32 code; 

    code=receive_data((thread_id *)&sender,(void *)&rdata,sizeof(rdata));
    Owner=rdata.owner;
    sock=rdata.sock;
        
    do{
        do{
            tv.tv_sec=2;
            tv.tv_usec=0;
            FD_ZERO(&fds);
                FD_SET(sock,&fds);
            select(32,&fds,NULL,NULL,&tv);
        } while(FD_ISSET(sock,&fds)==0);

        rec=recv(sock,buf,sizeof(buf),0);
        if(rec<=0)
        {
            sendmsg=new BMessage(MSG_VTCP_CLOSED);
            sendmsg->AddInt32("socket",sock);
                        
            Owner->PostMessage(sendmsg);
            delete sendmsg;     
        }
        else
        {
            sendmsg=new BMessage(MSG_VTCP_RECV);
            sendmsg->AddInt32("socket",sock);
            sendmsg->AddData("data",B_ANY_TYPE,(void *)buf,rec);

            Owner->PostMessage(sendmsg);
            delete sendmsg;     
        }
    } while(rec>0);

    return rec;
}
//---------------------------------------------------------------------

 残るはアクセプトの処理です。これはsock_connectと似た構成になっています。
connect関数の代わりにaccept関数を使用していること、acceptなのでアドレスの変換がないことぐらいでしょうか。
//---------------------------------------------------------------------
int VTcpNetworkClient::sock_accept(int s)
{
    struct sockaddr_in sa;
    int sa_size;
    
    sa.sin_family=AF_INET;
    memset(sa.sin_zero,0,sizeof(sa.sin_zero));
    sa_size=sizeof(sa);
    nsock=accept(s,(struct sockaddr *)&sa, &sa_size); 

    if(nsock!=-1)
    {
        struct RecThreadData rdata;
        
        rdata.sock=nsock;
        rdata.owner=MyOwner;
        if(MakeThreadName("ServerRecvThread",threadname))
        {
            recthread=spawn_thread(vtcp_rec_thread,threadname,
                        B_NORMAL_PRIORITY,NULL);
            send_data(recthread,63,(void *)&rdata,sizeof(rdata));
            resume_thread(recthread);
        }
        else
        {
            closesocket(nsock);
            nsock=-1; 
            return -1;
        } 
    }
    
    return nsock;
}
//---------------------------------------------------------------------


 これでVTcpNetworkClientクラスができあがりましたので、これをチェックするためのプログラムを作成します。と言っても、前回のプログラムとそれほど差はありません。listen以外の通信部分がVTcpNetworkClientクラスになっていることと、複数の接続を確認するために、使用するポートを10000と10001から選択できるように、チェックボックスを付けた程度です。

/**** ファイル名 : MainWindow.h ****/

#ifndef MAINWINDOW
#define MAINWINDOW
//---------------------------------------------------------------------
#include <Be.h>
#include <be/net/socket.h>
#include "vtcpnet.h"
//---------------------------------------------------------------------
#define MAINWINDOW_TITLE            "Network"
#define MAINWINDOW_POSITION_LEFT    100
#define MAINWINDOW_POSITION_TOP     100
#define MAINWINDOW_POSITION_WIDTH   400
#define MAINWINDOW_POSITION_HEIGHT  128
#define MAINWINDOW_WINDOWSTYLE      (B_TITLED_WINDOW)
//---------------------------------------------------------------------
#define MSG_CONNECT 'cnnb'
#define MSG_LISTEN  'lstb'
#define MSG_SEND    'sndb'
//---------------------------------------------------------------------
class BAppMainView : public BView
{
public:
    BStringView *strview;
    BTextControl *textctrl;
    BButton *connectbtn;
    BButton *listenbtn;
    BButton *sendbtn;
    BAppMainView(BRect frame);
    BCheckBox *portsw;
};
//---------------------------------------------------------------------
class BAppMainWindow : public BWindow
{
private:
    int nsock;
    VTcpNetworkClient *vtcp;
public:
    BAppMainView *mainview;
    //-----------------------------------------------------------------
    BAppMainWindow(BRect frame,const char *title);
    virtual void MessageReceived(BMessage *msg);
    //-----------------------------------------------------------------
    bool QuitRequested();
    //-----------------------------------------------------------------
    void sock_connect(void);
    void sock_listen(void);
    void sock_send(void);
};
//---------------------------------------------------------------------
#endif

/**** ファイル名 : MainWindow.cpp ****/

//---------------------------------------------------------------------
#include "MainWindow.h"
//---------------------------------------------------------------------
BAppMainWindow::BAppMainWindow(BRect frame,const char *title)
    :BWindow(frame,title,MAINWINDOW_WINDOWSTYLE,0)
{
    mainview=new BAppMainView(Bounds());        
    AddChild(mainview);

    nsock=-1;
    vtcp=NULL;
}
//---------------------------------------------------------------------
void BAppMainWindow::MessageReceived(BMessage *msg)
{
    switch(msg->what)
    {
        case MSG_SEND:
            sock_send();
            break;
        case MSG_CONNECT:
            sock_connect();
            break;
        case MSG_LISTEN:
            sock_listen();
            break;
        case MSG_VTCP_CLOSED:
            vtcp->sock_closed();
            mainview->strview->SetText("Disconnect"); 
            break;
        case MSG_VTCP_RECV:
            {
                char *buf;
                ssize_t leng;
                                
                msg->FindData("data",B_ANY_TYPE,(const void **)&buf,&leng);

                mainview->strview->SetText(buf);
            }
            break;
        default:
            BWindow::MessageReceived(msg);
    }
}
//---------------------------------------------------------------------
BAppMainView::BAppMainView(BRect frame)
    :BView(frame,"bappmainview",B_FOLLOW_ALL,B_WILL_DRAW)
{
    BRect viewrect(Bounds());
    connectbtn=new BButton(BRect(viewrect.right-144,8,
                                 viewrect.right-80,28),"connectbtn",
                                 "Connect",new BMessage(MSG_CONNECT),
                                     B_FOLLOW_RIGHT | B_FOLLOW_TOP);
    AddChild(connectbtn);
    listenbtn=new BButton(BRect(viewrect.right-72,8,
                                viewrect.right-8,28),"listenbtn",
                                "Listen",new BMessage(MSG_LISTEN),
                                B_FOLLOW_RIGHT | B_FOLLOW_TOP);
    AddChild(listenbtn);
    sendbtn=new BButton(BRect(viewrect.right-72,98,
                              viewrect.right-8,118),"sendbtn",
                              "Send",new BMessage(MSG_SEND),
                              B_FOLLOW_RIGHT | B_FOLLOW_TOP);
    AddChild(sendbtn);

    textctrl=new BTextControl(BRect(8,38,viewrect.right-8,58),"textctrl",
                              NULL,"Default",NULL,
                              B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
    AddChild(textctrl);

    strview=new BStringView(BRect(8,68,viewrect.right-8,88),"strview",
                            "NoData",
                            B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
    AddChild(strview);

    portsw=new BCheckBox(BRect(8,98,40,118),"portsw","On:A,Off:B",NULL);
    AddChild(portsw);

    textctrl->SetEnabled(false);
    sendbtn->SetEnabled(false);
}
//---------------------------------------------------------------------
void BAppMainWindow::sock_connect(void)
{
    mainview->connectbtn->SetEnabled(false);
    mainview->listenbtn->SetEnabled(false);

    vtcp=new VTcpNetworkClient(this);
        
    nsock=vtcp->sock_connect("127.0.0.1",
            10000+((mainview->portsw->Value()==B_CONTROL_ON)?1:0));

    if(nsock!=-1)
    {
        mainview->strview->SetText("Connect");    
        mainview->textctrl->SetEnabled(true);
        mainview->sendbtn->SetEnabled(true);
    }
}
//---------------------------------------------------------------------
void BAppMainWindow::sock_listen(void)
{
    int ssock;
    struct sockaddr_in sa;
    int sa_size;
    
    mainview->connectbtn->SetEnabled(false);
    mainview->listenbtn->SetEnabled(false);

    ssock=socket(AF_INET,SOCK_STREAM,0);

    sa.sin_family=AF_INET;
    sa.sin_port=htons(
        10000+((mainview->portsw->Value()==B_CONTROL_ON)?1:0));
    sa.sin_addr.s_addr=INADDR_ANY;
    memset(sa.sin_zero,0,sizeof(sa.sin_zero));
    bind(ssock,(struct sockaddr *)&sa,sizeof(sa)); 
    listen(ssock,5);
    sa_size=sizeof(sa);

    vtcp=new VTcpNetworkClient(this);
    nsock=vtcp->sock_accept(ssock); 
    closesocket(ssock);

    if(nsock!=-1)
    {
        mainview->strview->SetText("Connect");    
        mainview->textctrl->SetEnabled(true);
        mainview->sendbtn->SetEnabled(true);
    }
}
//---------------------------------------------------------------------
void BAppMainWindow::sock_send(void)
{
    int r;
    
    r=vtcp->sock_send((void *)mainview->textctrl->Text(),
                 (int32)strlen(mainview->textctrl->Text())+1);
    if(r==-1)
    {
        nsock=-1;
        mainview->strview->SetText("Disconnect");
    }
}
//---------------------------------------------------------------------
bool BAppMainWindow::QuitRequested()
{
    if(vtcp!=NULL)
        vtcp->sock_closed();
    
    be_app->PostMessage(B_QUIT_REQUESTED);
    return true;
};
//---------------------------------------------------------------------

 具体的な違いですが、ヘッダファイルでは、メッセージ定義がMSG_CONNECT、MSG_LISTEN、MSG_SENDの三つになったこと、RecThreadData構造体の定義がなくなったこと、BAppMainViewクラスにBCheckBox *portsw;が加わったこと、BAppMainWindowクラスにVTcpNetworkClient *vtcp;が加わったことぐらいでしょうか。

 MainWindow.cppの変更点は要点だけを説明します。
 BAppMainViewクラスのデストラクタには、
portsw=new BCheckBox(BRect(8,98,40,118),"portsw","On:A,Off:B",NULL);
AddChild(portsw);
と、「On:A,Off:B」と表記したチェックボックスを作成します。このチェックボックスがOnの場合はポートは10001を、Offの場合は10000を使用するようにします。
 あとは接続、送信、受信、アクセプトをそれぞれみてみましょう。
//---------------------------------------------------------------------
void BAppMainWindow::sock_connect(void)
{
    mainview->connectbtn->SetEnabled(false);
    mainview->listenbtn->SetEnabled(false);

    vtcp=new VTcpNetworkClient(this);
        
    nsock=vtcp->sock_connect("127.0.0.1",
            10000+((mainview->portsw->Value()==B_CONTROL_ON)?1:0));

    if(nsock!=-1)
    {
        mainview->strview->SetText("Connect");    
        mainview->textctrl->SetEnabled(true);
        mainview->sendbtn->SetEnabled(true);
    }
}
//---------------------------------------------------------------------
 まずは接続ですが、
vtcp=new VTcpNetworkClient(this);
でVTcpNetworkClientクラスのインスタントを作成し、
nsock=vtcp->sock_connect("127.0.0.1",
        10000+((mainview->portsw->Value()==B_CONTROL_ON)?1:0));
で接続先のアドレスとポートを指定して、sock_connect関数を実行します。戻り値はconnect関数の戻り値と同じですので、失敗した場合は-1となります。

//---------------------------------------------------------------------
void BAppMainWindow::sock_send(void)
{
    int r;
    
    r=vtcp->sock_send((void *)mainview->textctrl->Text(),
                 (int32)strlen(mainview->textctrl->Text())+1);
    if(r==-1)
    {
        nsock=-1;
        mainview->strview->SetText("Disconnect");
    }
}
//---------------------------------------------------------------------
 送信は、VTcpNetworkClientクラスのsock_send関数に送信するデータのアドレスとサイズを指定して実行するだけです。送信に失敗した場合は、ソケットをクローズしますので、MSG_VTCP_CLOSEDメッセージが通知されます。

//---------------------------------------------------------------------
void BAppMainWindow::MessageReceived(BMessage *msg)
{
    switch(msg->what)
    {
        case MSG_SEND:
            sock_send();
            break;
        case MSG_CONNECT:
            sock_connect();
            break;
        case MSG_LISTEN:
            sock_listen();
            break;
        case MSG_VTCP_CLOSED:
            vtcp->sock_closed();
            mainview->strview->SetText("Disconnect"); 
            break;
        case MSG_VTCP_RECV:
            {
                char *buf;
                ssize_t leng;
                                
                msg->FindData("data",B_ANY_TYPE,(const void **)&buf,&leng);

                mainview->strview->SetText(buf);
            }
            break;
        default:
            BWindow::MessageReceived(msg);
    }
}
//---------------------------------------------------------------------
 受信は、MSG_VTCP_RECVメッセージに受信データが付加されたかたちで通知されますので、FindData関数でデータを取得するだけです。
 また、ソケットがクローズされた場合(もしくは相手側から切断された場合)は、MSG_VTCP_CLOSEDメッセージが返ってきますので、その際はsock_closed関数を実行しておきます。

//---------------------------------------------------------------------
void BAppMainWindow::sock_listen(void)
{
    int ssock;
    struct sockaddr_in sa;
    int sa_size;
    
    mainview->connectbtn->SetEnabled(false);
    mainview->listenbtn->SetEnabled(false);

    ssock=socket(AF_INET,SOCK_STREAM,0);

    sa.sin_family=AF_INET;
    sa.sin_port=htons(
        10000+((mainview->portsw->Value()==B_CONTROL_ON)?1:0));
    sa.sin_addr.s_addr=INADDR_ANY;
    memset(sa.sin_zero,0,sizeof(sa.sin_zero));
    bind(ssock,(struct sockaddr *)&sa,sizeof(sa)); 
    listen(ssock,5);
    sa_size=sizeof(sa);

    vtcp=new VTcpNetworkClient(this);
    nsock=vtcp->sock_accept(ssock); 
    closesocket(ssock);

    if(nsock!=-1)
    {
        mainview->strview->SetText("Connect");    
        mainview->textctrl->SetEnabled(true);
        mainview->sendbtn->SetEnabled(true);
    }
}
//---------------------------------------------------------------------
 最後にアクセプト(サーバ側処理)ですが、アクセプトするためには、bind関数でソケットの準備をして、listen関数でクライアントからの接続を待つ必要があります。VTcpNetworkClientクラスはクライアントからの受信待ちはサポートしていないため、この部分は前回と同様に作成する必要があります。
 listen関数で受信待ちに使用されたssock変数を、sock_accept関数に渡すことでアクセプトされます。


 だいぶ間があいてしまいましたが、通信用のクラスもできあがり、通信もいよいよ大詰めです。あと一、二回いぐらいでメールチェックできるようにしたいですね。
ソースリスト
圧縮ファイル
R5 Intel環境で確認
Be9thApp20010214.zip
ソースファイル BaseApp.h
main.cpp
MainWindow.cpp
MainWindow.h
vtcpnet.cpp
vtcpnet.h

次の項目・・・作成中

トップページへ戻る