65.9K
CodeProject 正在变化。 阅读更多。
Home

使用网络开发套件 2.0 的简单文件传输

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.74/5 (14投票s)

2006年12月18日

2分钟阅读

viewsIcon

94779

downloadIcon

4747

NDK 文件传输是一个关于如何使用 NDK 2.0 发送和接收文件的简单演示。

Sample Image - NDKFileTransfer.jpg

引言

自从我发布了文章 NDK 2.0 (网络开发套件), 我收到了很多关于如何使用 NDK 发送和接收文件的电子邮件。 对于那些不了解网络开发套件 2.0 的人来说,NDK 2.0 是一组使用 MFC 的 CSocket 类的客户端-服务器架构的简单类。 通过本文,您应该能够轻松理解使用 NDK 发送和接收文件的过程。 本文包含 2 个程序:NDK 文件传输服务器和 NDK 文件传输客户端。

算法

您不能通过简单的调用通过网络发送大文件,因为套接字将冻结。 基本思想是将文件分成许多部分并一次发送一部分。 这是这两个程序使用的过程

  1. 客户端向服务器发送消息,请求下载特定文件。
  2. 当服务器收到请求时,它会发送要上传的文件的大小。
  3. 当客户端收到文件的大小后,它会创建下载的文件。
  4. 之后,它向服务器发送消息,请求文件的下一部分。
  5. 当服务器收到发送下一部分的请求时,它会读取文件的下一部分并将其发送给客户端。
  6. 当客户端收到文件的下一部分时,它会将这一部分写入下载的文件中。
  7. 步骤 4-5-6 重复,直到文件到达结尾。

在这个项目中,缓冲区大小(文件的一部分)是 1024 字节。 定义 BUFFER_SIZE 在文件 NDKFileTransferCommon.h 中。

NDK 文件传输服务器

NDK 文件传输服务器向客户端提供下载文件列表。 为了最大限度地减少复杂性,NDK 文件传输服务器只接受一个客户端。 在启动服务器之前,您需要单击“添加”按钮以选择客户端将可下载的文件。

NDKFileTransferServerDlg 中的主要方法是从 CNDKServer 类重写的 OnMessage 方法

// Called whenever a message is received from a user.
void CNDKFileTransferServerDlg::OnMessage(long lUserId, 
                              CNDKMessage& message)
{
    switch (message.GetId())
    {
    // The client requests a file to download
    case REQUEST_FILE:
        {
            CString strFileName;
            message.GetAt(0, strFileName);

            m_fileUpload.Open(strFileName, CFile::modeRead | 
                              CFile::shareDenyWrite);

            // Send the file length
            message.SetId(START_TRANSFERT);
            message.SetAt(0, (int)m_fileUpload.GetLength());

            SendMessageToUser(lUserId, message);

            CString strActivity;
            strActivity.Format(IDS_UPLOAD_FILE, strFileName);

            AddActivity(strActivity);
        }
        break;

    // The client asks for the next file part to download
    case REQUEST_NEXT_FILE_PART:
        {
            m_unBufferLength = m_fileUpload.Read(m_byteBuffer, BUFFER_SIZE);

            if (m_unBufferLength != 0)
            {
                // Send the file part
                message.SetId(NEXT_FILE_PART);
                message.SetAt(0, m_byteBuffer, m_unBufferLength);
            }
            else
            {
                // When there is no more read bytes,
                // send the acknowledgment that the file is completed
                message.SetId(TRANSFERT_COMPLETED);

                // Close the file if it is opened.
                if (m_fileUpload.m_hFile != INVALID_HANDLE_VALUE)
                    m_fileUpload.Close();

                CString strActivity;
                strActivity.Format(IDS_UPLOAD_FILE_COMPLETED);

                AddActivity(strActivity);
            }

            SendMessageToUser(lUserId, message);
        }
        break;
    }
}

NDK 文件传输客户端

NDK 文件传输客户端可以从服务器下载文件。 为了最大限度地减少复杂性,一次只能下载一个文件。

方法 OnBnClickedButtonDownloadFiles 包含用于请求服务器启动所选文件上传的代码

// Open the file
if (m_fileDownload.Open(strFileNameToCreate, 
    CFile::modeCreate | CFile::modeWrite))
{
    // Ask the server to start the download
    CNDKMessage message(REQUEST_FILE);
    message.Add(strFileName);

    SendMessageToServer(message);

    m_bIsDownloading = TRUE;

    UpdateUI();
}

NDKFileTransferClientDlg 中的主要方法是从 CNDKClient 类重写的 OnMessage 方法

// Called when a message is received.
void CNDKFileTransferClientDlg::OnMessage(CNDKMessage& message)
{
    switch (message.GetId())
    {
    case SERVER_FILES:
        {
            // Add the file name in the list
            for (int nFileIndex = 0; 
                 nFileIndex < message.GetNbElements(); nFileIndex++)
            {
                CString strFileName;

                message.GetAt(nFileIndex, strFileName);

                m_listServerFiles.AddString(strFileName);
            }

            UpdateUI();
        }
        break;

    case START_TRANSFERT:
        {
            message.GetAt(0, m_nFileSize);
            
            m_progressDownload.SetRange32(0, m_nFileSize);
            
            // Ask the server for the first file part
            message.SetId(REQUEST_NEXT_FILE_PART);
            SendMessageToServer(message);
        }
        break;

    case NEXT_FILE_PART:
        {
            message.GetAt(0, m_byteBuffer, m_unBufferLength);

            m_fileDownload.Write(m_byteBuffer, m_unBufferLength);

            m_progressDownload.OffsetPos(m_unBufferLength);

            // Ask the server for the first file part
            CNDKMessage requestMessage(REQUEST_NEXT_FILE_PART);
            SendMessageToServer(requestMessage);
        }
        break;

    case TRANSFERT_COMPLETED:
        m_fileDownload.Close();

        AfxMessageBox(IDS_FILE_DOWNLOADED_SUCCESSFULLY);

        UpdateUI();
        break;
    }
}

结论

这个示例项目向您展示了服务器如何将文件发送到客户端。 但是,此项目可以扩展为支持多个客户端、同时上传到连接的客户端以及服务器和客户端之间的双向文件传输。

© . All rights reserved.