|
Hello again,
i have made a server in a regular DLL, where the NDK2 derived server inserts received data into a buffer. In a worker thread i read the buffer works with the data and sends a responce back to the client.
When the server tries to send the responds back i get the following error:
The instruction at "0x00a39103" referenced memmory at "0x00000004". The memmory could not be "read"
The debug shows me that a ZERO pointer has sneaked into CAsyncSocket, and that the socket cannot be validated. Can anybody help me with this problem?
in advace thanks
Michael Olsen
|
|
|
|
|
I am not familiar with CSockets, so just looking at the source code of the NDK I cannot tell in advance what behaviour to expect. Additionally I cannot setup a realistic environment for testing. I will try to describe a scenario that hopefully describes my question.
Let's suppose that the server has to call SendMessageToAllUsers multiple times in a short time period. Looking at the source code, the user.SendMessage(message) will be called for each client. Suppose now, that a client is connected with a slow or busy connection. Is the next client "blocked" by this slow client??? Has the client to acknowledge that the message was received and everything is OK for the server to continue with the next client/message?? Please note that this does not have to be only a SendMessageToAllUsers example. This question also applies to multiple SendMessageToUser calls.
By the way is there a way to implement a time-out ??? (provided that is makes sense)
Thank you in advance for any input.
Warm regards
Pothitos M. Baikas
|
|
|
|
|
i dont know the answer for the first question (the one that takes 6 lines), but you dont have to worry about that.
there is a way to implement a timeout, and usually the timeout is 100 milliseconds (well, thats what the msdn says...)
i think the answer for the first question is yes, but not for a long time (1 second is quite fast)
its very simple to implement a timeout, just set a timer and send your message (dont forget to create a random number for your message and add that number to your message)
if timer has finished its job and you still didnt get that number from the server, it means the message wasn't sent or server couldn't send a message to you
if you got the number before the timer finished its job, you can kill it (the timer!).
simple, isn't it
Amir.
|
|
|
|
|
Hi, I have some problems while auto sending message from server to client,pleas see the following:
class CServer : public CNDKServer
{......
CMainFrame* m_pMainFrame;
CWinThread* m_pWinThread;
bool m_bIsThreadRun;
bool StartThread(void);
UINT SendDataToClient(void);
static UINT ControllingFunction(LPVOID pParam);
void GetAllData(void);
void GetOneData(void);
......
}
When Client requests auto send data, I create a thread to do this:
bool CServer::StartThread()
{
m_pWinThread = AfxBeginThread(ControllingFunction, this, THREAD_PRIORITY_NORMAL, 0 , CREATE_SUSPENDED, NULL);
if(m_pWinThread)
{
m_bIsThreadRun = true;
m_pWinThread->ResumeThread();
}
else
{
m_bIsThreadRun = false;
m_pMainFrame->m_Log.Log(LOG_ERROR, _T("Fail to start thread!"));
}
return m_bIsThreadRun;
}
UINT CServer::ControllingFunction(LPVOID pParam)
{
UINT nExitCode = ((CServer*)pParam)->SendDataToClient();
return nExitCode;
}
UINT CServer::SendDataToClient()
{
while(m_bIsThreadRun)
{
if(m_pMainFrame->m_Config.m_bIsAutoSendAll)
GetAllData();
else if(m_pMainFrame->m_Config.m_bIsAutoSendOne)
GetOneData();
Sleep(m_pMainFrame->m_Config.m_lSamplePeriod * 1000);
}
return 0;
}
And, GetAllData() GetOneData() calls SendMessageToUser(message).
Now, when sending a message, socket will get asserted:
#ifdef _DEBUG
void CAsyncSocket::AssertValid() const
{
CObject::AssertValid();
ASSERT(m_hSocket == INVALID_SOCKET || CAsyncSocket::FromHandle(m_hSocket) != NULL);
}
However, if CServer doesn't send message to client from multithread, it will OK.My app is based on MFC FormView, and CMainFrame class contains a CServer object, like this: CServer m_Server;
Also , I have patched the following code in the OnReceive() of CNDKServerSocket:
VERIFY(AsyncSelect(/*FD_READ | */FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE)); // CHANGE 1
...
CString strSockName = _T("");
UINT uiSockPort;
if(GetSockName(strSockName, uiSockPort) !=0)
VERIFY(AsyncSelect()); // CHANGE 2
(About this code: When I used WinCE & eVC, CCeSocket doesn't support AsyncSelect function, so I don't add the code. However, it works well in WinCE & eVC, I don't know why.)
I don't know the internal implenmention of the CSocket class, Can anyone help me? Thanks a lot!
|
|
|
|
|
Hello,
sorry for my bad english, i comes from germany and i have no train
yao_xuejun wrote:
#ifdef _DEBUG
void CAsyncSocket::AssertValid() const
{
CObject::AssertValid();
ASSERT(m_hSocket == INVALID_SOCKET || CAsyncSocket::FromHandle(m_hSocket) != NULL);
}
However, if CServer doesn't send message to client from multithread, it will OK.My app is based on MFC FormView, and CMainFrame class contains a CServer object, like this: CServer m_Server;
assertion refers to which the object internal structures for thread are invalid.
the problem is: all mfc-objects (like CSocket) was only thread-save on class-base, NOT on object-base. i mean, no objects can be used on a thread if the thread this object NOT have createt.
a solution is using the Detach() method from primary thread after Create, pass the handle from object to the thread and Attach() the handle to a new object. dont forget Detach() if the object no longer used in the secondary thread.
sample:
<br />
m_pWinThread = AfxBeginThread(ControllingFunction, this, THREAD_PRIORITY_NORMAL, 0 , CREATE_SUSPENDED, NULL);<br />
<br />
m_pWinThread->hSocket = m_Socket.Detach();<br />
<br />
if(m_pWinThread)<br />
{<br />
m_bIsThreadRun = true;<br />
m_pWinThread->ResumeThread();<br />
}<br />
... <br />
<br />
<br />
CSocket sock;<br />
sock.Attach( hSocket );<br />
this problem has many more objects from MFC on using with threads.
1) Detach() the object and forward the handle of this to the thread
2) create a new object and bind the handle (on 3) with a new object inside the thread
3a) use FromHandle() or
3b) use Attach() inside of the new thread thats using this object
use Attach() only if is guaranteed the fact that the corresponding object exists so long the thread works.
I hope this helps and you understand the problem
|
|
|
|
|
Thank you very much for your reply, I understand your means. But How to fix this when used in NDK2.0? "SOCKET" is inside the class, Anyway to correct this? Thanks a lot!
|
|
|
|
|
I modified the example of the server a little bit just to test a couple of things. What I did was to add some code to send messages to all connected clients in a rather rapid way using a timer event. The server and clients behaved as expected. The only problem appeared when a client decided to disconnect while the server kept sending messages. At this point the server crashed at the CNDKMessage::Serialize(CArchive& archive) because of a not valid archive (at least that's is how it looks to me). I am trying to find a way to overcome this problem by checking archive before proceeding. Is this the correct approach??? And if so can you please help ???
Warm regards
Pothitos
|
|
|
|
|
Unfortunately, I don't have the time to help you more using the NDK.
Did you overide the OnDisconnectUser in the chat server?
|
|
|
|
|
What I did was to add a
if (&archive == NULL)
{
ResetCurrentIndex();
return;
}
before proceeding. Seems to be working, although I am not sure if this the best approach.
Just hope that you will be able to look into this issue at a later time.
Warm regards and thanks for the excellent class.
|
|
|
|
|
I do not have the means to check it right now, so I would appreciate the author's opinion. If the client is behind a proxy, will it be able to communicate with the server (the server on a internet machine)
Warm regards
Pothitos M. Baikas
|
|
|
|
|
I think that the port number should be opened. This thing is related to network configuration not for CSocket.
|
|
|
|
|
Thank you for your response. I am glad to hear that it should work. For the situation I discibed I should have make clear in the input conditions that the port should be open.
Regards
|
|
|
|
|
If I use the direct internet connection - the Client works (at least connects to the Server in the Internet). When I hide a Client Behind a Proxy the connection function fails. What additional port manipulation must I do to make the Client work? Thank you.
|
|
|
|
|
It depends on the proxy or the firewall that you use. There is nothing you can do in the NDK side.
|
|
|
|
|
Hi,
i am writing a Client/Server program where the server are on a LAN, and the client connects over the internet.
When both apps are on the same lan there is no problem, but when the client connects over the internet it cannot find the server. Can anybody tell me what goes wrong and how to fix this?
|
|
|
|
|
You should give to the user the IP of your Internet connection not your LAN IP.
|
|
|
|
|
Sébastien Lachance wrote:
You should give to the user the IP of your Internet connection not your LAN IP
Well we have tried both adresses with the same result.
|
|
|
|
|
Could you try my game that is based on the NDK: www.rocler.qc.ca/netblitz/index.htm.
|
|
|
|
|
There is the issue with NDK library because the way how it receives data from non-blocking sockets.
The application that uses CSocket/CAsyncSocker class should make only one Receive call per OnReceive function. Otherwise it clears FD_READ notification and disables possible following OnReceive call.
One cannot avoid multiple calling of CSocket::Receive (ie recv) with CArchive and CSocketFile because CArchive does it internally by calling CSocketFile::Read when uncomplete mesage is being read.
It probably never happens with chat application nonetheless for higher transmission rate it makes NDK library unusable.
So how could we change the library to allow more frequest exchange of data? Since CNDKMessage interface is nice and it is worth to be kept (along with NDK's server User management) I suggest to use CMemFile as an intermediate storage place.
I am picturing it on CNDKClientSocket extension (see below).
If this idea draws an interest I can polish it out and add it to NDK.
Also, see Knowledge articale Q185728 for more complete reading about common programmers' MFC socket mistakes...
Radim Krampol
void CNDKClientSocket::SendMessage(CNDKMessage &msg)
{
BYTE* p = (BYTE *)malloc(4096);
CMemFile g(p, 4096, 256);
CArchive a(&g, CArchive::store);
msg.Serialize(a);
a.Flush();
long lLength = (long)g.GetLength();
BYTE* pBuffer = g.Detach();
BYTE* packet = new BYTE[lLength+4];
*((long*)(packet)) = lLength;
memcpy(packet+4, pBuffer, lLength);
int nWritten = CSocket::Send(packet, lLength+4);
a.Abort();
delete packet;
delete pBuffer;
if (nWritten == SOCKET_ERROR) {
int nError = GetLastError();
AfxThrowFileException(CFileException::generic, nError);
}
}
void CNDKClientSocket::ReceiveToBuffer()
{
BYTE buff[4096];
int nRead = CSocket::Receive(buff, 4096);
if (nRead == SOCKET_ERROR) {
int nError = CSocket::GetLastError();
AfxThrowFileException(CFileException::generic, nError);
}
m_buffer.Add(buff, nRead);
}
bool CNDKClientSocket::ReadMessage(CNDKMessage &msg)
{
if (m_buffer.IsMessage()) {
BYTE* p = m_buffer.GetMessage();
long l = m_buffer.GetMessageLength()-sizeof(long);
CMemFile g(p, l, 0);
CArchive a(&g, CArchive::load);
msg.Serialize(a);
m_buffer.RemoveMessage();
return true;
}
return false;
}
// Return if the buffer is empty.
bool CNDKClientSocket::IsBufferEmpty()
{
return !m_buffer.IsMessage();
}
// Suggested NDKMessage buffer interface
class CNDKBuffer
{
public:
CNDKBuffer();
virtual ~CNDKBuffer();
void Add(BYTE* p, int n);
bool IsMessage();
BYTE* GetMessage();
long GetMessageLength();
void RemoveMessage();
};
|
|
|
|
|
I am very interested in this. I'm using NDK in a project and I'm seeing occasional lockups (server seems to stop being able to send or receive messages until clients disconnect and reconnect). After reviewing the MSDN info you mentioned, I think that may be what the problem is.
My one question is about size limitations -- occasionally I need to send data that's multiple megabytes in size, so it would need to be able to handle this.
Thanks!
|
|
|
|
|
Stan -- you bet this's a reason of the lost data.
I will look into coding the proposed changes during the weekend provided noone will come with a better idea how to fix the library.
Any interest in it, Sebastian?
As for multimegabyte messages, it's obviously possible. On the application level you can just split the file into chunks and send them as NDK messages.
Nonetheless, the NDK library is great for exchanging of small and variable messages. I don't believe that the used communication model is good for exchanging huge data (an overhead, it fills up the communication channel).
How about using a separate socket, maybe even in a different thread?
Radim
|
|
|
|
|
I agree your idea. I have think about creating another thread to transmite huge files, but don't know how to implement this.
And, I meet another problem. While using NDK 2.0 in WinCE & eVC, I can't stop the socket. When I close application, it will hang. I just stop the listening socket in CMainFrame::OnClose, like this: m_Server.Stop();,but the application hangs. I don't know why? Is there any hint from you? Thanks a lot!
|
|
|
|
|
Radim,
Just FYI I'm trying the "quick fix" changes to OnReceive shown in this forum for now, I don't think the reported performance hit will affect my application. But I would much prefer a "real" solution such as you propose.
As for large messages, I have two issues:
1. In some cases I have to send several thousand strings at a time, with an average length of about 100 characters each. Breaking this up would mean some major code changes for me, but NDK handles it nicely as-is.
2. I have to transfer complete files several MB in size. For this I extended NDK to read/write a file directly. For the life of me I can't remember if I coded this myself or if someone else here contributed it, but here are the functions added to the code:
void CNDKDataBuffer::ReadBufferFromFile (LPCTSTR lpszFilename)
{
if (m_pData != NULL)
{
free(m_pData);
m_pData = NULL;
}
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
hFind = FindFirstFile(lpszFilename, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
m_unLength = FindFileData.nFileSizeLow;
FindClose(hFind);
OFSTRUCT ofstruct;
HFILE hFile = OpenFile (lpszFilename, &ofstruct, OF_READ);
if (hFile != HFILE_ERROR)
{
m_pData = malloc(m_unLength);
_lread (hFile, m_pData, m_unLength);
_lclose (hFile);
}
else
{
m_pData = NULL;
m_unLength = 0;
}
}
else
{
m_pData = NULL;
m_unLength = 0;
}
}
void CNDKMessage::ReadFromFile(LPCTSTR lpszFilename)
{
m_elements.Add(CNDKMessageData(lpszFilename));
}
CNDKMessageData::CNDKMessageData (LPCTSTR lpszFilename)
{
m_dataBuffer.ReadBufferFromFile (lpszFilename);
m_dataType = NDKDataBuffer;
}
BOOL CNDKMessageData::SaveAs (LPCTSTR lpszFilename) const
{
if (m_dataType == NDKDataBuffer)
{
OFSTRUCT ofstruct;
HFILE hFile = OpenFile (lpszFilename, &ofstruct, OF_CREATE | OF_WRITE);
if (hFile != HFILE_ERROR)
{
_lwrite (hFile, (char *) m_dataBuffer.GetBuffer(), m_dataBuffer.GetLength());
_lclose (hFile);
}
else
return FALSE;
}
return m_dataType == NDKDataBuffer;
}
Basically it uses the NDKDataBuffer type, but lets my code handle it like a file transfer:
case NMID_NetFile:
{
TCHAR *pszTempPath = new TCHAR[_MAX_PATH+2];
GetTempPath (_MAX_PATH, pszTempPath);
lstrcat (pszTempPath, "Temp.dat");
message.SaveAs (index++, pszTempPath);
}
break;
Sending file from server:
LRESULT CDlgNetServer::OnCmdSendFile (int nClient, LPCTSTR lpszFilename)
{
CNDKMessage messageOut (NMID_NetFile);
AddCommonHeader (messageOut);
messageOut.ReadFromFile (lpszFilename);
SendMessageToUser (nClient, messageOut);
return TRUE;
}
Hope that helps somebody.
Stan
|
|
|
|
|
It seems that you read a MB file into buffer and send at one time, Can large files be split into small parts and then be sent out? Thanks a lot!
|
|
|
|
|
Yes, this solution reads the file into a buffer and sends it all at once (though it is split into small packets at the socket/TCP level).
It would require coding *outside* of the NDK to handle splitting it up into multiple NDK messages, but I couldn't think of a reason to do this that was worth the effort of designing a file-packet-queing mechanism. It would take a lot of work to get something like that functioning smoothly, handling packets out of order, disconnects, missed messages, etc. etc. I figure the TCP designers already did that dirty work, why duplicate it?
Of course if the file is too large for available memory then it would make sense, or if you send lots of files at once.... but this wasn't an issue for me.
|
|
|
|
|