`
yimeng500
  • 浏览: 54637 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用CSocket创建C/S结构

阅读更多
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;
}

分享到:
评论

相关推荐

    利用CSocket类轻松实现C/S通讯

    本文将深入探讨如何利用MFC中的CSocket类来轻松实现C/S通讯。CSocket类是Microsoft Foundation Class (MFC) 库提供的一种简化套接字编程的工具,它基于Windows Socket API(Winsock)进行封装,使得程序员可以更方便...

    socket c/s 结构远程登录注册mfc

    3. **服务器端**:服务器监听特定端口,当收到连接请求时,使用Accept函数接受连接并创建新的CSocket对象。然后,服务器读取客户端发送的数据包。 4. **验证与响应**:服务器根据接收到的数据执行相应的逻辑,比如...

    用VC设计和实现C/S结构上的远程控制

    实现远程控制的关键是客户端/服务器(C/S)架构。在C/S架构中,客户端作为用户交互界面,发送请求给服务器;服务器接收到请求后,执行相应操作,并将结果反馈给客户端。在本文中,我们将讨论如何使用Microsoft ...

    C++编写的C/S聊天室程序

    在这个案例中,我们讨论的是一个用C++编程语言实现的C/S聊天室程序,它允许多个客户端连接到服务器,进行实时的群聊交流。 1. **C++基础知识**: C++是面向对象的编程语言,支持类、对象、封装、继承和多态等概念...

    c/s模式双机通讯/聊天软件

    1. 代码结构:典型的C/S程序包括客户端和服务器端两个部分,每个部分都有自己的主循环,负责处理网络事件。 2. 测试与调试:开发完成后,需要在不同环境下测试,确保软件在各种网络条件下能正常运行,并进行必要的...

    VC++ 邮槽实例,C/S结构实例

    通过阅读和分析这些代码,你可以深入理解如何在VC++中使用MFC实现C/S结构的邮槽概念,以及如何处理网络通信中的各种事件。同时,这也是一个很好的机会,可以学习如何调试网络应用程序,处理网络异常,以及优化通信...

    MFC聊天室(实现私聊)使用CSocket

    通过创建和使用CSocket对象,程序员能够建立客户端和服务器之间的连接,进行数据的发送和接收。在这个聊天室程序中,私聊功能的实现意味着用户可以选择与其他特定用户进行一对一的对话,而不干扰到其他用户。 私聊...

    毕业论文 基于CS结构局域网信息通信系统.doc

    1.2 C/S结构的优势 C/S架构的核心特点是将应用程序的功能分为两部分:客户端和服务器端。客户端负责用户交互,提供友好的用户界面,而服务器端则处理数据存储和管理,确保数据的安全性和一致性。这种结构使得系统...

    可控教师机学生机+源码

    总结来说,"可控教师机学生机"项目是一个基于C++和MFC的C/S结构的socket通信实例。它展示了如何利用CSocket类在教师机和学生机之间建立可靠的数据通道,实现远程控制和扫描功能。对于学习C++、网络编程以及MFC应用...

    MFC下客户端与服务器端的Socket通信(PPT)

    从 MFC 及其 Socket 类的基础介绍出发,深入探讨了 C/S 模式的具体实现方法,包括客户端与服务器端 Socket 的设计、工程创建、文件组织以及代码联结等方面的内容。此外,还简要讨论了 Socket 编程与第三方程序的互通...

    基于TCP的聊天程序设计与开发剖析.pdf

    1. 程序总体结构:C/S结构。C与S分开。 2. 服务器S程序基本构成:S主进程初始化;例如void CServerSocket::Start() { this-&gt;Create(1169); // 创建端口进程 this-&gt;Listen(); } 主进程进入监听;例如Listen();// ...

    服务器and客户端程序

    在IT领域,C/S(Client/Server)结构是一种常见的分布式应用架构,它将应用程序分为两个主要部分:客户端和服务器端。在这个系统中,"服务器and客户端程序"的实现通常涉及多个关键技术,包括MFC、多线程、数据库、...

    网络语音聊天系统的实现

    随着互联网技术的飞速发展,客户机/服务器(Client/Server,C/S)架构成为了现代网络应用的核心模式。在这种模式下,客户端向服务器请求服务,而服务器监听特定端口上的请求并提供相应的服务或响应。Winsock 2.0作为...

    MFC socket网络编程

    在MFC中,可以轻松地创建一个简单的C/S模式应用程序,实现特定的功能,如题目中提到的“手机控制电脑”的功能。 #### 7. 移动端网络编程 虽然本知识点主要针对PC端,但值得注意的是,Android网络编程同样可以使用...

    基于VC的局域网聊天室2.pdf

    【基于VC的局域网聊天室】是一种利用Visual C++ 6.0开发的网络通信应用,它基于TCP/IP协议,采用客户端/服务器(C/S)架构,旨在提供实时、有效的局域网内用户交流平台。该聊天室设计考虑了软件工程的方法,通过结构...

    网络编程实用教程(第三版).zip

    1.3.6 网络协议与C/S模式的关系 17 1.3.7 错综复杂的C/S交互 17 1.3.8 服务器如何同时为多个客户机服务 18 1.3.9 标识一个特定服务 20 1.4 P2P模式 21 1.4.1 P2P技术的兴起 21 1.4.2 P2P的定义和特征 ...

    计算机网络课设-基于TCP协议编程的网络聊天室.doc

    - 整个程序使用了CSocket类,这是MFC(Microsoft Foundation Classes)库提供的一个网络编程接口,简化了TCP通信的实现。 - 在C/S模式下,客户端通过连接效劳器的IP地址和端口进行通信。一旦连接建立,客户端可以...

    基于MFC的多人聊天室

    4. **C/S架构**:客户端/服务器架构,客户端与服务器通过网络进行通信。客户端发送请求,服务器接收请求并处理,然后返回响应。在这个聊天室中,客户端负责输入和显示消息,而服务器负责接收和转发消息。 5. **多...

    Visual C++6.0网络编程技术

    12.4 创建和使用自动化对象 236 12.5 部分源程序清单 240 第十三章 ActiveX自动化服务器 263 13.1 自动化服务器基础 263 13.2 创建自动化服务器框架工程 264 13.3 添加属性和方法 268 13.4 完成示例程序AutoDirInfo ...

Global site tag (gtag.js) - Google Analytics