|
NDK Standard
NDK in an Extension DLL
Introduction
With the success of NDK 1.0, I decided to improve the functionality. NDK represents Network Development Kit. The NDK is a set of classes that implements a client/server architecture. The NDK hides all the complexity of the connection, sending, and receiving of data over a network. You only have to deal with three classes: CNDKServer, CNDKClient, and CNDKMessage. With just a few methods to override, you obtain a complete robust client/server application. The NDK is based on the class CSocket from MFC, so you can run your application on a local network or on the Internet without any change. To easily understand the integration of the NDK in an application, you'll find at the end of this article a complete chat application.
Classes
CNDKServer: Server side of the client/server architecture
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: Client side of the client/server architecture
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: Encapsulation of the data that is sent and received by CNDKServer and CNDKClient
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);
Where TYPE can be a UCHAR, char, USHORT, short, UINT, int, long, float, double, CString, or LPVOID data.
What's new in 2.0
- Hungarian notation is used everywhere
CNDKServer notifies automatically CNDKClient when it disconnects and vice-versa
CNDKServer has new methods to send a message to a group of users
CNDKMessage is easier to use and more robust
- New methods to ping the server or the client
- NDK prefix added to all classes to make sure that all class names are unique in your project
- NDK is standalone or encapsulated in an extension DLL
Client/Server chat
Here are two screenshots of the chat application. Most features of the NDK are shown in both programs.


Sample code from the chat clientvoid CChatClientDlg::OnButtonSend()
{
if (UpdateData(TRUE))
{
CNDKMessage message(ChatText);
message.Add(m_strChatInput);
SendMessageToServer(message);
AddText(m_strChatInput);
m_strChatInput.Empty();
UpdateData(FALSE);
}
}
Sample code from the chat servervoid CChatServerDlg::OnMessage(long lUserId, CNDKMessage& message)
{
switch (message.GetId())
{
case ChatText:
{
CString strNickname;
m_mapIdsNicknames.Lookup(lUserId, strNickname);
CString strText;
message.GetAt(0, strText);
AddText(strNickname + _T(": ") + strText);
message.SetAt(0, strNickname);
message.SetAt(1, strText);
SendMessageToAllUsersExceptFor(lUserId, message);
}
break;
}
}
History
- 17 December 2006
- Fixed a bug in
NDKMessage concerning the length parameter of the GetAt and GetNext methods.
- 14 October 2005
- Telnet connections are now disconnected when a connection sends data to the server. Thanks to Stephan Douglas for the solution.
- Fixed a bug that resolves socket notification since the NDK uses Visual C++ .NET. After a short time, socket notifications were not send anymore.
- A verification is now made in the serialization of a
CNDKMessage to make sure that the message is really a CNDKMessage.
- Fixed a bug in the method
SendMessageToSomeUsers in the NDKServer.cpp.
- The project is now converted for Visual C++ .NET.
Fact
In 2002, the NDK was used in two NASA experiments for the Endeavor mission.
Conclusion
You don't have to be a guru of networking to create a client/server application, you only need to understand the above classes.
If you use the NDK in your project, I would really appreciate to receive an E-mail from you. I plan to make a web page of all programs using the NDK.
I would like to thank Yannick Létourneau who helped me in NDK 1.0.
Good Programming!
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 489 (Total in Forum: 489) (Refresh) | FirstPrevNext |
|
|
 |
|
|
I want use ndk to write a tcp server only,how can i use char[] instead of CNDKMessage when send and receive with other tcp client which donot use ndk
thanks!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
hi, it was a nice code. I'm still learning it. Anyway, could you somehow show me how to save into database when clients connected to server. I mean the timestamps, the duration of client connected to server and record timestamps when client disconnected from server. I just wondering how to do this. Thx for your help.
Learn from yesterday, live for today, hope for tomorrow
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi,Sébastien First i should thank you for your job~~i used it in my code,and it works very well! but there is an error when i use multithread.like this: i defind a struct first: struct RECPARAM { HWND hWnd; CNDKMessage message; long lUserId };
/***************************/ //then deal in OnMessage(): CXXXdlg::OnMessage(...) { ... case ..: RECPARAM *para=new RECPARAM; para->hWnd=m_hWnd; para->lUserId=lUserId; para->message=message; AfxBeginThread(MainFunc, para); break; } /*************/ //in the thread MainFunc:
UINT MainFunc(LPVOID pParam) { //long lUserId=...; CNDKMessage message=...; /***************** my functions; ******************/ // here i use SendMessageToUser(); SendMessageToUser(lUserId, message); }
when i use SendMessageToUser() here,there is a error: File:Wcore.cpp, Line:980; when i debug, i find in CNDKServer, the m_users can't find HeadPosition in Function GetUserFromId(); error happended here:POSITION pos=m_users.GetHeadPosition();
what's wrong with my code?  
I am looking foword for your answer~~~
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Great job on the code... works very well and easily extended.
I have a server running on Computer A which resides a couple of miles away. When trying to connect from Computer B, I am unsuccessful.
I use HughesNet (DirecWay) satellite internet and have both the local IP (within the local network) and the external IP address. Of course the local IP does not work but when I try the external IP, I get an "unable to connect" message.
I have disabled the firewalls and still the same. I can "ping" the server computer no problem, but connecting using NDK is not possible.
Any ideas? Can someone point me to code/articles that may help.
Thanks.. Tim
|
| Sign In·View Thread·PermaLink | 1.80/5 (2 votes) |
|
|
|
 |
|
|
Thanks for your nice work. I've used NDK for over 1 years, it's easy to use, but I meet some problems few days ago: If I send a message with a buffer over 1k size continously, the sending speed become very slow. Usually, 6~7 message sent fastly, followed with 1 message very slow(over 1.5sec), Why? I'v test your file transfer demo, it works but only reach 1.3MB/s over LAN, if I increase the message size the transfer speed become lower. How can I make it faster? Waiting for your response, thanks very much.
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Concerning the speed, I don't have a real control because I relied on CSocket from MFC.
Sébastien
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
If you replace the following code: VERIFY(AsyncSelect(/*FD_READ |*/ FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE)); with
VERIFY(AsyncSelect(FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE));
in CNDKServerSocket::OnReceive and CNDKClientSocket::OnReceive
sending and receiving become much faster!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
enum ThingType{NUL,CAR,HOUSE,TV,CPT}; struct SmallBlock { ThingType thing; bool IsMine; }
SmallBlock aBlock[10][9]
How can I send "aBlock" via NDKMessage ? I had spent alot of time to find out but still stucking. Plz help me !
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
Did you find the answer? I have it if you want. (I did not receive the CodeProject notification last month).
Sébastien
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hello. My name is Nick from Athens, Greece. I want to use this dll from vb.net (reference) but is not COM...
help my please
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi.. Thank you very much for your effort... But... Server module failed starting in Windows NT 4.0 platform..
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Did I read Windows NT 4.0? 
My NDK only uses MFC, so please check the code under MFC. Probably, the socket could not be allocated on Windows NT 4.0?!
Good luck, Sébastien
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Can you provide a slightest clear implementation of how to use CWinApp+NDKClient? I'd like to make it as a background/invisible application.
I've tried MFC-dialog+invisible but still a totally dirty code.
Thank you...
|
| Sign In·View Thread·PermaLink | 3.50/5 (2 votes) |
|
|
|
 |
|
|
you can try it in this way: 1:create a MFC-dialog app,named apptest for example 2:comment these code: // CApptestDlg dlg; // m_pMainWnd = &dlg; // int nResponse = dlg.DoModal(); // if (nResponse == IDOK) // { // // TODO: Place code here to handle when the dialog is // // dismissed with OK // } // else if (nResponse == IDCANCEL) // { // // TODO: Place code here to handle when the dialog is // // dismissed with Cancel // } and add MSG msg; while( GetMessage( &msg, NULL, 0, 0)) { DispatchMessage( &msg); } in the function CApptestApp::InitInstance() 3:class CApptestApp : public CWinApp, public CNDKServer
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
yay! thanks alot, I'm pretty confused where the message loop be put before.
This shows some light. Thanks again.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
first of all thank you for this usefull article.
I wrote a server client application, it worked fine, but when i tried to send number of messages at the same time the server applkication stops responding.
please help me to find the solution to that problem
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Under the CNDKClient and CNDKServer, I use the MFC class CSocket, so the problem is for sure inside the CSocket class. You'll have to debug CSocket.
Good luck! Sébastien
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Any luck finding the problem?
I too have started seeing the problem. If I send just a couple of messages once in a while, no problem, but if I send several (100+) messages (~200 bytes at the most) one right after the other, the server seems to hang.
I have noticed that if I "disconnect" from the client that sent the messages, the server immediately received all messages pending and at a very fast speed.
I have had no luck debugging this problem! Any help would be appreciated.
Tim tim@meadowcliff.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
First of all, NDK is definitively GREAT!!
But, from my point of view, it is too close to MFC in some low level classes like CNDKMessage & CNDKMessageData.
Why did you serialize the CNDKMessage object (in MFC way)? To manage versionning? Why not, but it's definitively too close to MFC. Personaly, I don't know how MFC serialize an CObject or an CNDKMessage! CObject serialization introduce an hard dependency on MFC. I use a C# and Java version of NDK, and I remove this serialization, else that impossible to read/write an NDKMessage.
Other problem: about CNDKMessageData::Serialize, for other data type than NDKDataString and NDKDataBuffer you just write/read a copy-memory of union!! Well, good luck to read that in java/c#!!! And write/read 8 bytes for a byte, it's maybe too much, isn't it? And, what about the network byte order?
Do you think that possible to make some modifications to make NDK more usable on other platform than Wintel?
regards,
Matt
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks for your comment. My goal when making the NDK was to do a layer over CSocket. I did not intend to port it in JAVA/C#/Other OS.
Sébastien
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi! I'm Lee!
Before question, I thank you for your excellent job! It's really help me.
Ok! My problem is Message Map. I work on VC++6.0, and I try to use message map, error occur.
-------- error ----------------------------------------------------- error C2440: 'type cast' : cannot convert from 'void (__thiscall CSkyAndong_SubDlg::*)(unsigned int,long)' to 'long (__thiscall CWnd::*)(unsigned int, long)' -------- error -----------------------------------------------------
Please, Find way to use message map.
Thank you!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hum.
in "ChatServerDlg.h"
#define WM_TEST_MESSAGE WM_USER + 100 // define this message ... afx_msg void OnButtonPingUser(); afx_msg void OnButtonStart(); afx_msg void OnButtonPingAllUsers(); afx_msg void OnButtonDisconnectAllUsers(); //}}AFX_MSG afx_msg void OnTestMessage(UINT nID, LPARAM lParam); // declaration function DECLARE_MESSAGE_MAP()
in "ChatServerDlg.cpp"
ON_BN_CLICKED(IDC_BUTTON_PING_USER, OnButtonPingUser) ON_BN_CLICKED(IDC_BUTTON_START, OnButtonStart) ON_BN_CLICKED(IDC_BUTTON_PING_ALL_USERS, OnButtonPingAllUsers) ON_BN_CLICKED(IDC_BUTTON_DISCONNECT_ALL_USERS, OnButtonDisconnectAllUsers) //}}AFX_MSG_MAP ON_BN_CLICKED(IDCANCEL, &CChatServerDlg::OnBnClickedCancel) ON_MESSAGE(WM_TEST_MESSAGE, OnTestMessage) // Add Message to Message Map END_MESSAGE_MAP()
after compile
error C2440: 'static_cast' : cannot convert from 'void (__thiscall CChatServerDlg::*)(UINT,LPARAM)' to 'LRESULT (__thiscall CWnd::*)(WPARAM,LPARAM)'
error occur...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|