doing5552

记录每日点滴,不枉人生一世

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  73 Posts :: 0 Stories :: 94 Comments :: 0 Trackbacks

公告

常用链接

留言簿(24)

我参与的团队

最新随笔

搜索

  •  

积分与排名

  • 积分 - 454135
  • 排名 - 47

最新随笔

最新评论

阅读排行榜

评论排行榜

CSocket派生于CAsyncSocket, 所有施诸于上的操作皆为同步操作。比如Connnect,Receive等。
同步操作的优点是简单易用,但缺点也显而易见,效率低下,因为你必须等到一个操作完成之后才能进行下一个操作。
如果你很关心效率,就应该优先使用CAsyncSocket。反之就用CSocket。
下面将说明如何用CSocket创建简单的服务器和客户端。

[创建服务器]

服务器的运作有5个阶段:
1. 创建服务器Socket并开启监听。
2. 获取新的客户端连接Socket,将之加入客户端Socket列表以管理之。
3. 客户端Socket读取数据并发送数据。
4. 客户端连接被动关闭,从列表删除。
5. 程序关闭,进而服务器连接主动关闭。

为了维持5阶段的运作,需要两种Socket协同工作, 第一种用作服务器监听(负责步骤1,2,5),第二种用作客户端管理(负责步骤3,4)。
两种Socket皆派生自CSocket, 通过重写不同的CSocket成员函数以实现不同的功能。

前者需要在服务器初始化阶段创建出来CSocket::Create()并开启监听CSocket::Listen()(步骤1)。并在服务器退出时主动关闭连接CSocket::Close()(步骤5)。
前者还需要重写OnAccept以在新的客户端连接到来时被通知,同时产生客户端管理Socket(步骤2)。

 

后者需要重写OnReceive以在有数据到来时被通知,或重写OnClose以在连接被动关闭(客户端关闭)时被通知(步骤3,4)。

读写数据需要CSocketFile以及CArchieve的支持。前者将CSocket当作一个文件,后者则完成在此文件上的读写操作。
通常你需要添加一个CSocketFile成员,两个CArchieve成员(一个用于读,一个用于写),然后在Socket创建完成后初始化这些成员

socketFile_ = new CSocketFile( this ); // 在archive创建出来后基本上就不需要操作他了,直到Socket关闭
archiveIn_ = new CArchive( socketFile_, CArchive::load ); // 用于读
archiveOut_ = new CArchive( socketFile_, CArchive::store ); // 用于取

并在OnRecevie中用archiveIn_读取数据,用archiveOut_写入数据。像这样:
int value;
archiveIn_ >> value;
archiveOut_ << value * value;

下面是比较完整的Server端的源代码:

//---------------------------------------------------------------------------------
// CServerDoc.cpp
//---------------------------------------------------------------------------------
BOOL CServerDoc::OnNewDocument()
{
    ...
    serverSocket_ = new CServerSocket( this );
    serverSocket_->Create( 5001 );
    serverSocket_->Listen( 5 );
    return TRUE;
}

void CServerDoc::DeleteContents()
{
    // TODO: Add your specialized code here and/or call the base class
    delete serverSocket_;
    serverSocket_ = NULL;

    // 主动断开连接
    // release all client sockets
    POSITION position = clientSockets_.GetHeadPosition();
    while ( position != NULL ) {
        delete clientSockets_.GetNext( position );
    }
    clientSockets_.RemoveAll();

    CDocument::DeleteContents();
}

void CServerDoc::OnAccept()
{
    CClientSocket* newClientSocket = new CClientSocket( this );
    serverSocket_->Accept( *newClientSocket );
    newClientSocket->Initialize();
    clientSockets_.AddTail( newClientSocket );
}

// 被动断开连接
void CServerDoc::OnClose( CClientSocket* clientSocket )
{   
    POSITION position = clientSockets_.Find( clientSocket );   
    clientSockets_.RemoveAt( position );
    delete clientSocket;
}

void CServerDoc::OnReceive( CClientSocket* clientSocket )
{
    // receive data with clientSocket  
}

//---------------------------------------------------------------------------------
// CServerSocket.cpp
//---------------------------------------------------------------------------------
CServerSocket::CServerSocket( CServerDoc* document )
: document_( document )
{
}

CServerSocket::~CServerSocket()
{
}

void CServerSocket::OnAccept(int nErrorCode)
{
    // TODO: Add your specialized code here and/or call the base class
    document_->OnAccept();
    CSocket::OnAccept(nErrorCode);
}

//---------------------------------------------------------------------------------
// CClientSocket.cpp
//---------------------------------------------------------------------------------
CClientSocket::CClientSocket( CServerDoc* document )
: document_( document )
, socketFile_( NULL )
, archiveIn_( NULL )
, archiveOut_( NULL )
{
}

CClientSocket::~CClientSocket()
{
    delete archiveIn_;
    archiveIn_ = NULL;

    delete archiveOut_;
    archiveOut_ = NULL;
   
    // 必须在删除archive以后删除
    delete socketFile_;
    socketFile_ = NULL;   
}

void CClientSocket::OnClose(int nErrorCode)
{
    // TODO: Add your specialized code here and/or call the base class   
    CSocket::OnClose(nErrorCode);
    document_->OnClose( this ); // 一定要在最后一行
}

void CClientSocket::OnReceive(int nErrorCode)
{
    // TODO: Add your specialized code here and/or call the base class
    document_->OnReceive( this );
    CSocket::OnReceive(nErrorCode);
}

BOOL CClientSocket::Initialize()
{
    socketFile_ = new CSocketFile( this );
    archiveIn_ = new CArchive( socketFile_, CArchive::load );
    archiveOut_ = new CArchive( socketFile_, CArchive::store );
    return TRUE;
}

[创建客户端]

客户端的运作比服务器简单
1. 创建客户端Socket并连接到服务器。 CSocket::Create() -> CSocket::Connect()
2. 客户端Socket读取数据并发送数据。   CSocket::OnReceive()
3. 客户端连接被动关闭。                        CSocket::OnClose()
4. 程序关闭,进而客户端连接主动关闭。CSocket::Close()

下面是比较完整的Client端的源代码:

//---------------------------------------------------------------------------------
// CClientDlg.cpp
//---------------------------------------------------------------------------------
CClientDlg::CClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CClientDlg::IDD, pParent)
    , socket_( NULL )   
{
    ...
}

void CClientDlg::OnDestroy()
{
    CDialog::OnDestroy();

    // TODO: Add your message handler code here
    // 主动断开连接
    delete socket_;
    socket_ = NULL;
}

void CClientDlg::OnBnClickedConnnect()
{
    // TODO: Add your control notification handler code here
    UpdateData( TRUE );

    socket_ = new CClientSocket( this );
    socket_->Create();

    if ( !socket_->Connect( "127.0.0.1", 5001 ) ) {
        delete socket_;
        socket_ = NULL;
        MessageBox( _T( "连接失败" ) );
        return;
    }
    socket_->Initialize();
}

// 主动断开连接
void CClientDlg::OnBnClickedDisconnect()
{
    // TODO: Add your control notification handler code here
    delete socket_;
    socket_ = NULL;
}

// 被动断开连接
void CClientDlg::OnClose()
{
    delete socket_;
    socket_ = NULL;
    MessageBox( _T("服务器断开") );   
}

void CClientDlg::OnReceive()
{
    // receive data with socket_
}

//---------------------------------------------------------------------------------
// CClientSocket.cpp
//---------------------------------------------------------------------------------
CClientSocket::CClientSocket( CClientDlg* dialog )
: dialog_( dialog )
, socketFile_( NULL )
, archiveIn_( NULL )
, archiveOut_( NULL )
{
}

CClientSocket::~CClientSocket()
{
    delete archiveIn_;
    archiveIn_ = NULL;
    delete archiveOut_;
    archiveOut_ = NULL;
    delete socketFile_;
    socketFile_ = NULL;
}

void CClientSocket::OnClose(int nErrorCode)
{
    // TODO: Add your specialized code here and/or call the base class   
    CSocket::OnClose(nErrorCode);
    dialog_->OnClose();
}

void CClientSocket::OnReceive(int nErrorCode)
{
    // TODO: Add your specialized code here and/or call the base class
    dialog_->OnReceive();
    CSocket::OnReceive(nErrorCode);
}

BOOL CClientSocket::Initialize()
{
    socketFile_ = new CSocketFile( this );
    archiveIn_ = new CArchive( socketFile_, CArchive::load );
    archiveOut_ = new CArchive( socketFile_, CArchive::store );
    return TRUE;
}

posted on 2010-01-12 20:47 doing5552 阅读(463) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理