|
Need help to understand this line of code
step = (struct MyStep*)BigStep
given,
typedef struct MyStep {...structure definition...};
const struct MyStep BigStep[]{...an array of MyStep...};
Thank you
|
|
|
|
|
I don't know what version of C/C++ that is but it looks wrong to me. Why not show the exact code that you are trying to understand?
Unrequited desire is character building. OriginalGriff
I'm sitting here giving you a standing ovation - Len Goodman
|
|
|
|
|
That:
- Takes
BigStep (the address of the array of const MyStep structs ). - Casts it to
struct Mystep * (hence discarding the const constraint). - Assigns the result to
step (that is probably defined as struct MyStep * ).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Hi,
Ebe72 wrote: step = (struct MyStep*)BigStep given, typedef struct MyStep {...structure
definition...}; const struct MyStep BigStep[]{...an array of MyStep...};
Sorry, but by itself, this is Absolutely Meaningless. Firmware, Hardware, or Software Coding, makes no Real difference. It is something written in 'C'.
Question 1. Does your Code Compile.
If it does, you're lucky!
Question 2.
Does your code do what it is supposed to do.
If the answer is 'Yes' set a number of breakpoints around where the structure is used, and that will soon tell you (May take some patience) what happens, and what's what.
If your code does not Compile, you probably left out a Header. If it compiles, but does not link, you left out Library References.
If it Compiles and Links, but does not do what you expect, go back to the Docks and find out what it was supposed to do in the First Place!
Set Breakpoints, and find out what's going on.
This is a process called 'Debugging' It takes Time Skill and cunning, and the gray cells of 'Hercule Poirot'. It cannot be thaught as such, but you get experienced with your best friend, your Compiler.
Famous Chestnuts:-
<br />
if(x=0){...Do Something...} (Never Happens)<br />
<br />
int x==1;<br />
<br />
for(x=0;x=10;x++){...Do Something...}<br />
switch(){
break;<br />
}<br />
Hope this helps, if not, we need to see a little bit more than two lines of code, part of a Structure Definition. We are Not mindreaders
Bram van Kampen
|
|
|
|
|
BigStep[] is an array of MyStep structures. BigStep is a pointer to that array, iem the address of the first storage hole. ie, &BigStep[0].
'step as (MyStpe*)BigStep' points another pointer, this one a non const I assume (depending on how 'step' is declared), to the same address.
(BTW with the typedef you dont need to use ctruct MyStep* as the cast, MyStep* alone will compile since it is a new defined type.)
==============================
Nothing to say.
|
|
|
|
|
In VC6 when we use ::ifstream.open("test.txt") call creates a file if the specified file is not found in the location. But in VS2010 it does not create a file when its not found. Why is this differece and how to resolve this problem?
|
|
|
|
|
It looks VS2010 is more 'compliant' (see ifstream::open[^]).
It doesn't look a problem to me, however you may provide the second argument with the open mode you wish, if you need.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
i m wonderring which second argument option will work like as vc6.
|
|
|
|
|
Try them out to see which one works as desired... do you really need people to do all the thinking for you?
if the default is ios_base::in (see parameters):
void open ( const char * filename, ios_base :openmode mode = ios_base::in );
then just try making it ios_base::out (if you're only writing to it, or in/out if you're reading and writing).
open(filename, ios_base::out);
open(filename, ios_base::in | ios_base::out);
|
|
|
|
|
Even i tried all this and posted here when things are not working.
None of the above options creates a file when its not found. only VC6 open does.
|
|
|
|
|
if you're using the ifstream version, it sort of implies that you're pulling in data (thus, why would you want to create a file if it doesn't exist)... did you try to fstream/ofstream version of open? did you try putting in the whole path to the file to see if that made a difference?
Basic debugging... come on...
|
|
|
|
|
finally i confirmed that vc6 ifstream::open has bug and this has been fixed in vs2010. So i modified the code to match with existing behaviour.
|
|
|
|
|
I wrote a scalable TCP server using I/O completion ports. The basic design is that I kick off an accept thread that waits forever for the FD_ACCEPT network event and then accepts the connection and ties it to the I/O completion port. There are 4 to 8 worker threads that process events coming off the I/O completion port. Everything works great.
Now I'm trying to add scalable UDP support. I am new to UDP, so I'm not sure how I should go about this.
1) if I have 4 to 8 worker threads to process TCP events coming off the I/O completion ports, should I do the same for UDP? Some links I found said you only need one thread for UDP and there is no need for IOCPs??? This seems wrong as say I get 1000 UDP events at the same time, I'd like to be able to multi-thread process them.
2) I don't seem to get any network events when a UDP client "connects", just get the FD_OOB at "start up".
Was kind of expecting this to behave like the TCP side in which I'd get a network event when the client "connects" and then another event when there is data to read (via WSAEnumNetworkEvents())...
I know UDP is connectionless, but I'm not getting any network events when the server gets data.
|
|
|
|
|
UDP is connectionless, so you did not get a connect event. But you can get events when data arrives. Using one receiving thread is enough even with many clients when the UDP packets are small. A typical implementation would be:
m_hevWSA = ::WSACreateEvent();
m_sockRecv = ::WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);
::bind(m_sockRecv, reinterpret_cast<sockaddr*>(&sinRecv), sizeof(struct sockaddr));
UINT CMyClass::WorkerThread(void)
{
int nRet = -1;
bool bPending = false;
DWORD dwWSARead = 0;
DWORD dwWSAFlags = 0;receive flags
char NetBuf[DGRAM_BUF_SIZE];
WSABUF WSABuf = { DGRAM_BUF_SIZE, NetBuf };
HANDLE ahWait[2] = { m_evKill.m_hObject, m_hevWSA };
WSAOVERLAPPED ovWSA;
struct sockaddr_in SenderAddr;
::ZeroMemory(&SenderAddr, sizeof(SenderAddr));
::ZeroMemory(&ovWSA, sizeof(WSAOVERLAPPED));
ovWSA.hEvent = m_hevWSA;
do
{
int nWSAErr = 0;
unsigned nNetRead = 0;
if (!bPending)
{
dwWSARead = 0;
dwWSAFlags = 0;
WSABuf.len = DGRAM_BUF_SIZE;
WSABuf.buf = NetBuf;
int nSenderAddrSize = sizeof(SenderAddr);
if (::WSARecvFrom(m_sockRecv, &WSABuf, 1, &dwWSARead, &dwWSAFlags,
(SOCKADDR *)&SenderAddr, &nSenderAddrSize, &ovWSA, NULL) == 0)
{
nNetRead = static_cast<unsigned>(dwWSARead);
}
else
{
nWSAErr = ::WSAGetLastError();
if (nWSAErr == WSA_IO_PENDING)
bPending = true;
else
nRet = 1;
}
} switch (::WaitForMultipleObjects(bPending ? 2 : 1,
ahWait, FALSE, bPending ? INFINITE : 0))
{
case WAIT_OBJECT_0 : nRet = 0; break;
case WAIT_OBJECT_0 + 1 :
if (::WSAGetOverlappedResult(m_sockRecv, &ovWSA, &dwWSARead, FALSE, &dwWSAFlags))
{
nNetRead += static_cast<unsigned>(dwWSARead);
bPending = false;
}
else
{
nWSAErr = ::WSAGetLastError();
if (nWSAErr != WSA_IO_INCOMPLETE)
bPending = false;
}
::ResetEvent(m_hevWSA);
break;
}
if (nNetRead)
{
}
}
while (nRet == -1);
return (nRet == STILL_ACTIVE) ? 1 : static_cast<UINT>(nRet);
}
|
|
|
|
|
Thanks Jochen. A follow up question:
Jochen Arndt wrote: Using one receiving thread is enough even with many clients when the UDP packets
are small.
What specifics are we talking here? Seems like common convention on the internet is telling me to restrict UDP packet sizes to 256 bytes, correct?
Assuming my UDP server is receiving AND sending to clients, how many clients can I handle in a single thread? 100? 1,000? 10,000? 100,000?
Basically trying to do something that could scale to millions of clients. Not even sure if thats possible without multiple servers behind a load balancer though .
|
|
|
|
|
SledgeHammer01 wrote: What specifics are we talking here? Seems like common convention on the internet is telling me to restrict UDP packet sizes to 256 bytes, correct?
Yes. Bigger packets may be used when only a few packets are expected (clients * rate).
SledgeHammer01 wrote: Assuming my UDP server is receiving AND sending to clients, how many clients can I handle in a single thread? 100? 1,000? 10,000? 100,000?
It depends on many things. At least the server should be able to process all packets according to the available network bandwidth. If the server has low resources, additional threads would not help. If data processing after receiving is time consuming, using multiple threads for processing may be an option. With TCP connections, threads are used to unlock the port for new connections. This is not necessary with UDP.
SledgeHammer01 wrote: Basically trying to do something that could scale to millions of clients. Not even sure if thats possible without multiple servers behind a load balancer though
Using a load balancer is common practice if a single server could not handle all requests.
|
|
|
|
|
Thank you very much.
One final question . Seems like a common UDP loop is pretty similiar to the common TCP loop:
while (1)
{
int i = recvFrom(...);
// do stuff
}
so, I may be misunderstanding, but say I have 10,000 clients in say a game perhaps, or whatever. They might send me a "here is my new position" UDP packet and then I'd have to send out a "here is user x's new position" UDP packet.
So with a single thread, wouldn't the loop be something like:
while (1)
{
int i = recvFrom(...);
UpdatePosition(recvBuff);
for (int j = 0; j < 10000; j++)
SendPositionUpdate();
}
if I got 100 position updates, I'd have to send out 10000 * 100 position updates to the clients (I know there is multi-cast , but I'm trying to figure out the basic concept at this point ).
point is... I'd have to finish sending out recv #1's 10000 notification packets before I ever got to servicing recv #2??
Maybe I need to get all available recv's in each iteration and then just send out 10000 notifications once?
Just trying to figure out how this stuff is implemented in the real world .
|
|
|
|
|
The loop is similar. I don't know how it is done with game servers. For sending packets, you should use non-blocking calls. These return immediately and you did not have to wait.
You may also use an own thread for sending. Then you must only call a signaling function from within the receive thread. If the sending thread has not finished sending all data when new data should be send, you can skip the new data, terminate the actual transmission loop and restart it with the new data, or just use the new data for the outstanding transmissions. I think the last option would be the best solution for positions with a game server.
|
|
|
|
|
Gotcha... thanks! 5's all around .
|
|
|
|
|
Thank you too.
Did you find the problem? When I tried to send an answer, the message was gone.
|
|
|
|
|
Jochen Arndt wrote:
Thank you too. Did you find the
problem? When I tried to send an answer, the message was gone.
Yeah... as I indicated originally, I was adding UDP support to my working TCP IOCP server. I neglected to mention that it was IP agnostic (Ipv4 & Ipv6) . So passing in a sockaddr_in was too small a buffer for the Ipv6 addresses, so it kicked it out. Switched it over to the correct SOCKADDR_STORAGE and its working now.
Thanks again!
|
|
|
|
|
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.
|
|
|
|
|