Introduction
Since I have posted the article NDK 2.0 (Network Development Kit), I received many emails on how to send and receive a file using the NDK. For those who does not know the Network Development Kit 2.0, the NDK 2.0 is a set of simple classes for a client-server architecture using the class CSocket
from MFC. With this article, you should be able to understand easily the process about sending and receiving a file with the NDK. This article contains 2 programs: an NDK File Transfer Server and an NDK File Transfer Client.
Algorithm
You can not send a big file with a simple call to over a network, because the socket will freeze. The basic idea is to split a file in many parts and send one part at a time. Here is the process used by these two programs:
- The client sends a message to the server asking to download the specific file.
- When the server receives the request, it sends the length of the file to upload.
- When the client receives the length of the file, it creates the downloaded file.
- After that, it sends a message to the server asking for the next part of the file.
- When the server receives the request to send the next part, it reads the next part of the file and it sends it to the client.
- When the client receives the next part of the file, it writes this part in the downloaded file.
- The steps 4-5-6 are repeated until the file will reach the end.
In this project, the buffer size (part of the file) is 1024 bytes. The define BUFFER_SIZE
is in the file NDKFileTransferCommon.h.
NDK File Transfer Server
The NDK File Transfer Server provides to the client a list of files in download. To minimize the complexity, the NDK File Transfer Server accepts only one client. Before starting the server, you need to click the Add button in order to choose the files that will be available to download by the client.
The main method in the NDKFileTransferServerDlg
is the overridden method OnMessage
from the class CNDKServer
:
void CNDKFileTransferServerDlg::OnMessage(long lUserId,
CNDKMessage& message)
{
switch (message.GetId())
{
case REQUEST_FILE:
{
CString strFileName;
message.GetAt(0, strFileName);
m_fileUpload.Open(strFileName, CFile::modeRead |
CFile::shareDenyWrite);
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;
case REQUEST_NEXT_FILE_PART:
{
m_unBufferLength = m_fileUpload.Read(m_byteBuffer, BUFFER_SIZE);
if (m_unBufferLength != 0)
{
message.SetId(NEXT_FILE_PART);
message.SetAt(0, m_byteBuffer, m_unBufferLength);
}
else
{
message.SetId(TRANSFERT_COMPLETED);
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 File Transfer Client
The NDK File Transfer Client can download a file from the server. To minimize the complexity, only one file at a time can be downloaded.
The method OnBnClickedButtonDownloadFiles
contains the code to ask the server to start the upload of the selected file:
if (m_fileDownload.Open(strFileNameToCreate,
CFile::modeCreate | CFile::modeWrite))
{
CNDKMessage message(REQUEST_FILE);
message.Add(strFileName);
SendMessageToServer(message);
m_bIsDownloading = TRUE;
UpdateUI();
}
The main method in the NDKFileTransferClientDlg
is the overridden method OnMessage
from the class CNDKClient
:
void CNDKFileTransferClientDlg::OnMessage(CNDKMessage& message)
{
switch (message.GetId())
{
case SERVER_FILES:
{
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);
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);
CNDKMessage requestMessage(REQUEST_NEXT_FILE_PART);
SendMessageToServer(requestMessage);
}
break;
case TRANSFERT_COMPLETED:
m_fileDownload.Close();
AfxMessageBox(IDS_FILE_DOWNLOADED_SUCCESSFULLY);
UpdateUI();
break;
}
}
Conclusion
This sample project shows you how a server can send a file to a client. However, this project can be extended to support multiple clients, simultaneous uploads to connected clients, and both ways transfer of a file between the server and the client.