|
Hmm... seems like its not working after all This is what I do:
1) WSAStartup() and m_hIOCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
2) getaddrinfo() to get the IPv4 & IPv6 interfaces
3) for each on items returned from getaddrinfo() WSASocket(...WSA_FLAG_OVERLAPPED) and bind()) and CreateIoCompletionPort((HANDLE)socket, m_hIOCompletionPort, (DWORD)pClientContext, 0); foreach worker thread (I have 8), I post a WSARecvFrom()
step #3 is executed twice... once for the ipv4 socket and once for the ipv6 socket
ISSUE #1: the WSARecvFrom always returns -1 and WSAGetLastError is 997 (IO pending), I don't think thats quite right??
ISSUE #2: in my workerthread, I do:
BOOL bReturn = GetQueuedCompletionStatus(m_hIOCompletionPort, &dwBytesTransferred,
(LPDWORD)&pClientContext, &pOverlapped, INFINITE);
I get past this blocking call and dwBytesTransferred = 3 which is correct since my client just sent "0\r\n".
so I call WSARecvFrom() and again, I get -1 and IO pending?
|
|
|
|
|
Error 997 / IO_PENDING is not an error. It is the normal return value when no data are available (non-blocking call, WSARecvFrom() returns always immediately). When returned, you have to wait until data has been received and copied to the buffer which is signaled by the socket handle passed to the overlapped struct. After calling WSAGetOverlappedResult() you can call WSARecvFrom() again. Don't call WSARecvFrom() again while the previous call returned the pending state! Before calling it again, the read count and flag parameter variables must be cleared, because they contain values from the previous receive.
That's the reason why I posted a rather big code block. All lines are necesarry to make it work. When using the example code without any processing of the received data, the time consumed by the thread is insignificant. Receiving occurs in the background and the thread is only activated when data has been read into the buffer.
|
|
|
|
|
I think that is what I'm doing ... I am using the network notifications w/ IOCP though. So in my start up I do:
m_hIOCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
when I create the socket, I do:
SOCKET socket = WSASocket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (bind(socket, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen) == SOCKET_ERROR)
{
...
}
CreateIoCompletionPort((HANDLE)socket, m_hIOCompletionPort, (DWORD)pClientContext, 0);
for (int nIndex = 0; nIndex < m_nThreadCount; nIndex++)
{
SOCKADDR_STORAGE addr;
addr.ss_family = AF_UNSPEC;
addr.__ss_align = 0;
int nAddrLen = sizeof(SOCKADDR_STORAGE);
DWORD dwBytesSent = 0;
DWORD dwFlags = 0;
char szBuffer[MAX_BUFFER_SIZE];
ZeroMemory(szBuffer, sizeof(szBuffer));
WSABUF wsaBuf;
wsaBuf.buf = szBuffer;
wsaBuf.len = sizeof(szBuffer);
OVERLAPPED overlapped;
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
int nResult = ::WSARecvFrom(socket, &wsaBuf, 1, &dwBytesSent, &dwFlags, (sockaddr*)&addr,
&nAddrLen, &overlapped, NULL);
int nError = WSAGetLastError();
}
The worker thread func looks like:
while (WaitForSingleObject(m_hShutdownEvent, 0) != WAIT_OBJECT_0)
{
CClientContext* pClientContext = NULL;
OVERLAPPED* pOverlapped = NULL;
DWORD dwBytesTransferred = 0;
DWORD dwFlags = 0;
WSABUF* pWSABUF = NULL;
BOOL bReturn = GetQueuedCompletionStatus(m_hIOCompletionPort, &dwBytesTransferred,
(LPDWORD)&pClientContext, &pOverlapped, INFINITE);
SOCKADDR_STORAGE from;
int nFromLen = sizeof(SOCKADDR_STORAGE);
memset(&from, 0, sizeof(SOCKADDR_STORAGE));
int nBytesRecv = -1;
nBytesRecv = WSARecvFrom(pClientContext->GetSocket(), pWSABUF, 1, &dwBytesTransferred,
&dwFlags, (sockaddr*)&from, &nFromLen, pOverlapped, NULL);
int j = WSAGetLastError();
int k = 0;
}
}
|
|
|
|
|
Try my code without using GetQueuedCompletionStatus() and waiting for data using WaitForMultipleObjects() . The code has been copied from an existing application.
I have never used GetQueuedCompletionStatus() , because blocking functions may cause problems. E.g. your shut down event will be only processed after the blocking function returns. If the network connection of the system drops, this will never occur.
To test your code, you should check the return value of GetQueuedCompletionStatus() , and test if bytes has been read (dwBytesTransferred ).
You should also test your code with only one thread first to ensure that problems are not sourced by using multiple threads. In your code you are starting 8 receives in a loop where each uses the same variables. I'm not sure if that is working.
Another point:
int nBytesRecv = -1;
nBytesRecv = WSARecvFrom(pClientContext->GetSocket(), pWSABUF, 1, &dwBytesTransferred, &dwFlags, (sockaddr*)&from, &nFromLen, pOverlapped, NULL);
int j = WSAGetLastError();
WSARecvFrom() does not return the number of bytes reads. It returns 0 upon success. Upon success you should not call GetLastError() because it returns the most recent error which may be from any previous called function that fails. Alternatively, you can call SetLastError(0) before executing a function that may set an error value.
|
|
|
|
|
Jochen Arndt wrote: I have never used GetQueuedCompletionStatus() , because blocking
functions may cause problems. E.g. your shut down event will be only processed
after the blocking function returns. If the network connection of the system
drops, this will never occur.
That case is actually handled, although I did not post that snippet . The method that sets the shutdown event also posts an I/O completion message so that it exits the blocking function (copied from MSFT sample code).
Jochen Arndt wrote: To test your code, you should check the return value of
GetQueuedCompletionStatus() , and test if bytes has been read
(dwBytesTransferred ).
Yes, GetQueuedCompletionStatus() returns true and says there are 3 bytes transferred which is correct since the client is sending "0\r\n".
Jochen Arndt wrote: You should also test your code with only one thread first to ensure that
problems are not sourced by using multiple threads. In your code you are
starting 8 receives in a loop where each uses the same variables. I'm not sure
if that is working.
Yes, for the TCP side of things, this is not an issue because each client is going to new up a CClientContext and get its own buffer.
For the UDP side of things, yes, I understand this will be an issue and that code needs to be refactored / fixed since it will create a CClientContext for the SERVER socket (I just did this to get the code fundamentally going through the same logic flow). Although for now, just testing with a single client sending a single packet .
Jochen Arndt wrote: WSARecvFrom() does not return the number of bytes reads. It returns
0 upon success. Upon success you should not call GetLastError()
because it returns the most recent error which may be from any previous called
function that fails. Alternatively, you can call SetLastError(0)
before executing a function that may set an error value.
Understood. Just for testing since WSARecvFrom is returning -1. .
For testing again, I set m_nThreadCount to 1, so only 1 worker thread is used. Same issue. dwTransferredBytes = 3. BufferLen = 256, Data is empty. Return value is -1. from is not filled. pOverlapped has everything 0 except the Internal flag which is set to 259.
WSAGetLastError = 997.
I will experiment with your code some more unless you have other ideas?
|
|
|
|
|
One simple question: Is data empty before you call the next RecvFrom() ? If not, all is working. The next RecvFrom() call returns the pending state when there are no new data (the previous packet has been already received).
|
|
|
|
|
Yes, the WSABuf is initialized and empty before each WSARecvFrom call. It always returns -1 / 997.
|
|
|
|
|
Made an interesting discovery!! Changed the code to look like:
pOverlapped->hEvent = WSACreateEvent();
int nBytesRecv = WSARecvFrom(pClientContext->GetSocket(), pWSABUF, 1, &dwBytesTransferred,
&dwFlags, (sockaddr*)&from, &nFromLen, pOverlapped, NULL);
WaitForSingleObject(pOverlapped->hEvent, INFINITE);
Now, when I send it "0\r\n" ONE time, it blocks on the WaitForSingleObject forever. If I send it a SECOND "0\r\n", it now passes the WaitForSingleObject() and has the 0\r\n in the buffer! what the heck??? Its like one behind or something.
|
|
|
|
|
Hmm.. another discovery . It is not one packet behind. It is just not getting the first packet for some reason. If I send it "0\r\n", "1\r\n", "2\r\n", 1 and 2 work, but 0 does not.
|
|
|
|
|
ARGH!! found the problem. I had a fundamental misunderstanding of the logic flow when using I/O completion ports. The TCP side was working, but not in the way I thought it was . The UDP side is also working now.
Basically with I/O completion ports, you ALWAYS get a IO pending on sends & recvs. The GetQueuedCompletionStatus() function operates like a wait. On the TCP side, I created a new CClientContext for each connection which is correct and thus the WSABUF was passed around correctly. On the UDP side, I can't have the shared buffer obviously because it all comes from multiple clients at the same time. So I need to derive a new struct from OVERLAPPED and add the shared members there for UDP and pass that around.
Basically once you get the GetQueuedCompletionStatus() notification, the buffer is already full (assuming you still have access to it -- in my current design, I didn't). Then you call wsarecvfrom AGAIN and it'll start a new overlapped call until new data is available, then GetQueuedCompletionStatus() will return again and so on.
Thanks again for your help.
|
|
|
|
|
Fine that you find the problem.
SledgeHammer01 wrote: So I need to derive a new struct from OVERLAPPED and add the shared members there for UDP and pass that around.
I expected something like that.
|
|
|
|
|
I have ported a DLL project from VC6 -> VS2010. It gives the following link error.
LINK : error LNK2001: unresolved external symbol __DllMainCRTStartup@12
How to resolve this error?
|
|
|
|
|
|
it compiles in vc6. Only in vs2010 link error.
|
|
|
|
|
so, check your vs2010 settings. confirm that it's linking with the MS runtimes.
|
|
|
|
|
yes. It seems like some MS library links by default in vc6 but not in vs2010. Will have investigate further. Thanks for your info.
|
|
|
|
|
KASR1 wrote: How to resolve this error?
See here. It almost sounds like a Unicode issue. Do you have UNICODE and/or _UNICODE defined?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous
modified 30-Jan-12 12:44pm.
|
|
|
|
|
i was able to compile the project in vc6, it gives error only in VS2010(after porting). Something related to environment. I couldnot get it
|
|
|
|
|
It wasn't Unicode, was it? Well I'm betting it is now. Sounds wrong entry point for a Unicode app.
Steve
|
|
|
|
|
Hello All,
I have a mfc application. I have an ActiveX control qualitycontrol.ocx.I want to load a dialog of that ActiveX control and call it's methods on button click of my mfc application.
Please help me how to do that?
|
|
|
|
|
Right click on a dialog and select Insert ActiveX Control .
|
|
|
|
|
First of all thank you for replying. But when I right -click on the dialog and 'insert activeX control' it shows windows activeX control but I want to include my own activeX control "qualityControl.ocx" and call a memeber function defined in that control.
Please help me how to do that.
Adity
|
|
|
|
|
Is your control visible in the Insert ActiveX Control Listbox?
if not then you have not registered the activeX control. You need to put that control in Windows->System32 and open it using Regsvr32.exe. which is available in the same folder. And now you need to try again right clicking the mouse and selecting the "Insert ActiveX Control"
Once it is available select the control and then you can create a member variable for that and call the necessary member functions through that member variable.
Every new day is another chance to change your life.
|
|
|
|
|
Hi,
yes I have registered the control and added header file and .cpp file of that control using Add-> class->MFC from ActiveX into my project. I created a member variable of that class by the following code on button click of my application
CQualityCheck chkdlg;
chkdlg.callSample("");
but while running it is showing error in the following code winocc.cpp file:
void AFX_CDECL CWnd::InvokeHelper(DISPID dwDispID, WORD wFlags, VARTYPE vtRet,
void* pvRet, const BYTE* pbParamInfo, ...)
{
ASSERT(m_pCtrlSite != NULL); // not an OLE control (not yet, at least)
if (m_pCtrlSite == NULL)
return;
va_list argList;
va_start(argList, pbParamInfo);
m_pCtrlSite->InvokeHelperV(dwDispID, wFlags, vtRet, pvRet, pbParamInfo,
argList);
va_end(argList);
}
Please help how to resolve this?
Adity
|
|
|
|
|
The list that you see is not Windows ActiveX Controls.
They are all the registered ActiveX controls.
Like Chandrasekharan said, you need to register the ActiveX control using regsvr32.exe
However, you do not need to place it in the system32 folder.
You can place it in any folder.
|
|
|
|
|