使用NDK进行网络文件传输
来源:互联网 发布:数据挖掘岗很难进吗 编辑:程序博客网 时间:2024/05/22 10:50
Sebastien_Lachance写了一个名为NDK (Network Development Kit 2.0) 的小工具,可以方便的开发客户服务器程序。提供了一个服务器、客户端的框架,基于MFC的CSocket的,不足的是只支持单线程,多线程也不安全。NDK隐藏了基于网络开发的复杂性,只用和3个类进行交互:CNDKServer、CNDKClient、CNDKMessage。先简单看下这些类:
CNDKServer
Attributes:
· BOOL IsStarted() const;
· long GetPort() const;
· long GetNbUsers() const;
· void GetUserIds(CLongArray& alIds) const;
Operations:
· BOOL StartListening(long lPort);
· void Stop();
· BOOL SendMessageToUser(long lUserId, CNDKMessage& message);
· BOOL SendMessageToAllUsers(CNDKMessage& message);
· BOOL SendMessageToSomeUsers(const CLongArray& alUserIds, CNDKMessage& message);
· BOOL SendMessageToAllUsersExceptFor(long lUserId, CNDKMessage& message);
· BOOL SendMessageToAllUsersExceptFor(const CLongArray& alUserIds, CNDKMessage& message);
· BOOL DisconnectUser(long lUserId);
· void DisconnectAllUsers();
· BOOL PingUser(long lUserId);
· void PingAllUsers();
Callbacks:
· virtual BOOL OnIsConnectionAccepted() = 0;
· virtual void OnConnect(long lUserId) = 0;
· virtual void OnMessage(long lUserId, CNDKMessage& message) = 0;
· virtual void OnDisconnect(long lUserId, NDKServerDisconnection disconnectionType) = 0;
· virtual void OnPing(long lUserId, long lNbMilliseconds);
CNDKClient
Attributes:
· BOOL IsConnected() const;
· BOOL GetIpAndPort(CString& strIp, long& lPort) const;
Operations:
· BOOL OpenConnection(const CString& strServerIp, long lPort);
· void CloseConnection();
· BOOL SendMessageToServer(CNDKMessage& message);
· BOOL PingServer();
Callbacks:
· virtual void OnMessage(CNDKMessage& message) = 0;
· virtual void OnDisconnect(NDKClientDisconnection disconnectionType) = 0;
· virtual void OnPing(long lNbMilliseconds);
CNDKMessage
Attributes:
· void SetId(long lId);
· long GetId() const;
· int GetNbElements() const;
Operations:
· void Add(TYPE typeData);
· void SetAt(long lIndex, TYPE typeData);
· void GetAt(long lIndex, TYPE& typeData) const;
· void GetNext(TYPE& typeData);
TYPE 可以是 UCHAR, char, USHORT, short, UINT, int, long, float, double, CString, 或者 LPVOID,这为我们开发各种应用提供了方便。有兴趣的可以读读其源码。通过使用CArchive来实现常用数据类型的序列化和反序列化,然后通过网络进行传输。
CNDKMessage有一个属性ID来代表消息的类型,重载纯虚函数virtual void OnMessage(CNDKMessage& message) = 0时,可以根据消息类型不同而进行不同的处理。比如我们做一个聊天程序可以定义如下消息:
enum ChatMessage{ChatUserJoin,ChatUserQuit,ChatText,ChatBigMessage};
然后在OnMessage中进行处理:
void CChatServerDlg::OnMessage(long lUserId, CNDKMessage& message){switch (message.GetId()){case ChatUserJoin:{……}break;case ChatText:{……}break;case ChatBigMessage:{……}break;}}
如何利用这个框架来实现文件的传输?由于一次传输的数据包不能过大,文件肯定是需要分片的。定义如下的消息类型:
// Defines use for CNDKMessage#define SERVER_FILES 0#define REQUEST_FILE 1#define START_TRANSFERT 2#define REQUEST_NEXT_FILE_PART 3#define NEXT_FILE_PART 4#define TRANSFERT_COMPLETED 5// Define use when allocating the buffer to send a file part#define BUFFER_SIZE 1024
SERVER_FILES 用以获取服务器上可用的文件列表。REQUEST_FILE用于请求某个文件,可以多个。START_TRANSFERT用于获取文件大小,以便分配磁盘空间。REQUEST_NEXT_FILE_PART客户端请求下一个文件块。NEXT_FILE_PART服务器发送下一个文件块。TRANSFERT_COMPLETED 文件传输结束。BUFFER_SIZE表示文件的分片大小。
服务器端的代码如下:
// 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; }}
客户端首先请求一个文件:
// Open the fileif (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();}
然后重载CNDKClient中的virtual void OnMessage(CNDKMessage& message) = 0;
// 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; }}
更多信息和源码参见:
http://www.codeproject.com/KB/IP/peer_to_peer_communicator.aspx
http://www.codeproject.com/KB/IP/ndk.aspx
http://www.codeproject.com/KB/IP/NDKFileTransfer.aspx
- 使用NDK进行网络文件传输
- 使用串口进行文件传输
- 使用Netty进行文件传输
- 使用TFTP进行文件传输
- 使用Netty进行文件传输
- 使用secureCRT进行文件传输
- 使用 Thrift 进行文件传输
- 使用gFTP进行安全文件传输
- cocos2dx 使用libcurl进行文件传输
- 使用FTP自动进行文件传输
- 使用C#进行点对点通讯和文件传输
- 使用C#进行点对点通讯和文件传输
- 使用 JSR-82 和 OBEX 进行文件传输
- 使用C#进行点对点通讯和文件传输
- 使用 JSR-82 和 OBEX 进行文件传输
- 使用 JSR-82 和 OBEX 进行文件传输
- 使用C#进行点对点通讯和文件传输
- 使用scp在Linux之间进行文件传输
- 大数据量算法
- hdu 3689 Infinite monkey theorem
- 本地计算机上的OracleOraHome92Agent服务启动后又停止了
- 在内核中创建文件 filp_open/sys_open
- 2010武汉IT环境~
- 使用NDK进行网络文件传输
- usaco contact
- Prime算法
- cocoa 文件操作
- V4L2采集摄像头数据
- Java集合中常用的接口和类
- SQL/PLUS学习笔记
- java invoke 2【动态调用类的方法】
- Lucene.Net的学习心得