|
There is something wrong?!
post a read request after put SOCKET_EVENT_TYPE_CLOSE event !!!
see somewhere comments
//edit by xiny120 never make a read request after close 05-11-06 00:25:00
void OIOCPNet::IOWorker(DWORD ExeCode, DWORD IOSize, OVERLAPPEDExt *pOVLEx)
{
BOOL bError;
OBufferedSocket *pBuffSock;
DWORD Flag;
int ResRecv;
int ResSend;
DWORD ErrorCode;
OSafeLocker SLock(m_pWriteBlock->GetBlockLock());
OBufferedSocket *pBuffSockToWrite;
DWORD ReadSizeToWrite;
BOOL DoesItHaveMoreSequence;
DWORD WrittenSizeUseless;
OTemporaryWriteData *pTempWriteData;
bError = 0;
if (1 == InterlockedExchange((long *)&m_dStop, m_dStop))
{
goto ErrHand;
}
if (0 != ExeCode)
{
// When OIOCPNet stops, ExeCode has an error code.
}
//if (0 == pOVLEx)
//{
// ErrorCode = GetLastError();
// if (ERROR_NETNAME_DELETED == ErrorCode) // server side close. close socket because of the result of writing, timeout, etc... // ERROR_NETNAME_DELETED The specified network name is no longer available.
// {
// // the close of this server itself. (close socket because of the result of writing)
// // or closesocket by client, suddenly. 'Write -> (no Read) closesocket' on client.
// InterlockedIncrement((long *)&g_CloseByRead);
// m_pReadSlot->Put(SOCKET_EVENT_TYPE_CLOSE, pBuffSock, 0, 0); // pBuffSock's SocketUnique is needed when close.
// }
// else
// {
// m_pEL->ErrLog(ERRLOC, "GetQueuedCompletionStatus is failed. Error Code = %d", ErrorCode);
// }
// goto ErrHand;
//}
if (STATUS_WRITE_FROM_Q == (DWORD)pOVLEx)
{
pBuffSock = 0;
}
else
{
if (0 != pOVLEx && (IO_TYPE_WRITE == pOVLEx->IOType || IO_TYPE_WRITE_LAST == pOVLEx->IOType))
{
if ((IO_TYPE_WRITE_LAST == pOVLEx->IOType || IO_TYPE_WRITE == pOVLEx->IOType))
{
if (0 != pOVLEx->pTempWriteData)
{
m_SMMTempWriteData.Free(pOVLEx->pTempWriteData);
}
goto ErrHand;
}
}
else if (STATUS_BEFORE_ACCEPT == pOVLEx->IOType)
{
pBuffSock = pOVLEx->pBuffSock;
ZeroMemory(&pBuffSock->OLExt, sizeof (pBuffSock->OLExt));
pBuffSock->OLExt.pBuffSock = pBuffSock;
pBuffSock->OLExt.IOType = STATUS_ACCEPT;
if (0 == m_lpfnAcceptEx(m_ListeningSocket, pBuffSock->Socket,
reinterpret_cast<void*>(const_cast<byte*>(pBuffSock->BufferForAccept)), 0,
sizeof (sockaddr_in) + 16, sizeof (sockaddr_in) + 16, &pBuffSock->AcceptBytes, (LPOVERLAPPED)&(pBuffSock->OLExt)))
{
ErrorCode = WSAGetLastError();
if (WSA_IO_PENDING != ErrorCode)
{
m_pEL->ErrLog(ERRLOC, "WSAAcceptEx is failed. Error Code = %d",ErrorCode);
bError = 1;
goto ErrHand;
}
}
goto ErrHand;
}
else if (STATUS_ACCEPT == pOVLEx->IOType)
{
pBuffSock = pOVLEx->pBuffSock; // So bad AcceptEx! pBuffSock was not assigned correctly at PostQueued... for AcceptEx.
if (RET_FAIL == ChangeSocketModeAfterAccept(pBuffSock->Socket))
{
m_pEL->ErrLog(ERRLOC, "ChangeSocketModeAfterAccept is failed.");
InterlockedIncrement((long *)&g_CloseByRead);
m_pReadSlot->Put(SOCKET_EVENT_TYPE_CLOSE, pBuffSock, 0, 0);
goto ErrHand;//edit by xiny120 never make a read request after close 05-11-06 00:25:00
}
/////////////
/*
SOCKADDR_IN *sockAddr=NULL,*sal=NULL;
int nSal=0,nSockAddrLen=0;
typedef struct _TA_ADDRESS {
USHORT AddressLength;
USHORT AddressType;
UCHAR Address[1];
} TA_ADDRESS, *PTA_ADDRESS;
typedef struct _TRANSPORT_ADDRESS {
LONG TAAddressCount;
TA_ADDRESS Address[1];
} TRANSPORT_ADDRESS, *PTRANSPORT_ADDRESS;
sockaddr_in * pin = (sockaddr_in *)(&(((TRANSPORT_ADDRESS *)(pBuffSock->BufferForAccept+4))->Address[0].AddressType));
m_lpfnGetAcceptExSockAddrs(pBuffSock->BufferForAccept,0,sizeof (sockaddr_in)+16,sizeof (sockaddr_in)+16,
(sockaddr **)&sal,&nSal,(sockaddr **)&sockAddr,&nSockAddrLen);
// nPeerPort = ntohs(sockAddr->sin_port);
// strncpy(szPeerAddress,inet_ntoa(sockAddr->sin_addr),nLen);
////////////////////////////*/
InterlockedIncrement((long *)&m_ActiveConnectionNum);
goto RecvPoint;
}
else
{
pBuffSock = pOVLEx->pBuffSock;
}
}
if (0 != pBuffSock)
{
if (0 == IOSize && 0 != pOVLEx && STATUS_BEFORE_ACCEPT != pOVLEx->IOType
&& STATUS_ACCEPT != pOVLEx->IOType)
{
InterlockedIncrement((long *)&g_CloseByRead);
m_pReadSlot->Put(SOCKET_EVENT_TYPE_CLOSE, pBuffSock, 0, 0); // pBuffSock's SocketUnique is needed when close.
goto ErrHand; // Don't run into the read mode.
}
if (0 != pOVLEx)
{
if (IO_TYPE_READ == pOVLEx->IOType)
{
if (RET_FAIL == m_pReadSlot->Put(SOCKET_EVENT_TYPE_READ, pBuffSock, (BYTE *)pBuffSock->BufferReadIO.buf, IOSize))
{
m_pEL->ErrLog(ERRLOC, "Put is failed.");
// Illegal packet, release the content of pBuffSock.
InterlockedIncrement((long *)&g_CloseByRead);
m_pReadSlot->Put(SOCKET_EVENT_TYPE_CLOSE, pBuffSock, 0, 0);
goto ErrHand;//edit by xiny120 never make a read request after close 05-11-06 00:25:00
}
}
}
else
{
m_pEL->ErrLog(ERRLOC, "Odd operation.");
goto ErrHand;
}
}
else
{
if (STATUS_WRITE_FROM_Q == (DWORD)pOVLEx)
{
SLock.Lock();
do
{
// pTempWriteData will be freed when send IO ends.
pTempWriteData = (OTemporaryWriteData *)m_SMMTempWriteData.Allocate(sizeof (OTemporaryWriteData));
if (0 == pTempWriteData)
{
m_pEL->ErrLog(ERRLOC, "Allocate is failed.");
bError = 1;
goto ErrHand;
}
// the size of pData (the second parameter of GetBlockNeedsExternalLock) does not be over BUFFER_UNIT_SIZE.
m_pWriteBlock->GetBlockNeedsExternalLock(&pBuffSockToWrite, pTempWriteData->Data, &ReadSizeToWrite, &DoesItHaveMoreSequence);
pTempWriteData->Socket = pBuffSockToWrite->Socket;
pTempWriteData->DataBuf.buf = (char *)pTempWriteData->Data;
pTempWriteData->DataBuf.len = ReadSizeToWrite;
pTempWriteData->OLExt.pTempWriteData = pTempWriteData;
pTempWriteData->OLExt.pBuffSock = pBuffSock;
if (1 == DoesItHaveMoreSequence)
{
pTempWriteData->OLExt.IOType = IO_TYPE_WRITE;
}
else
{
pTempWriteData->OLExt.IOType = IO_TYPE_WRITE_LAST;
}
Flag = MSG_PARTIAL;
try
{
ResSend = WSASend(pTempWriteData->Socket, &pTempWriteData->DataBuf, 1, &WrittenSizeUseless, Flag, (LPOVERLAPPED)&pTempWriteData->OLExt, 0);
}
catch (...)
{
// suddenly, the BuffSock was closed and released by PreAllocator. Ignore...
SLock.Unlock();
goto ErrHand;
}
if (SOCKET_ERROR == ResSend)
{
ErrorCode = WSAGetLastError();
if (WSA_IO_PENDING != ErrorCode)
{
if (WSAECONNRESET == ErrorCode || WSAECONNABORTED == ErrorCode
|| WSAESHUTDOWN == ErrorCode || WSAENETRESET == ErrorCode)
{
if (0 == DoesItHaveMoreSequence)
{
InterlockedIncrement((long *)&g_CloseByWrite);
m_pReadSlot->Put(SOCKET_EVENT_TYPE_CLOSE, pBuffSockToWrite, 0, 0);
goto ErrHand;//edit by xiny120 never make a read request after close 05-11-06 00:25:00
}
}
else
{
m_pEL->ErrLog(ERRLOC, "WSASend is failed. Error Code = %d", ErrorCode);
if (0 == DoesItHaveMoreSequence)
{
InterlockedIncrement((long *)&g_CloseByWrite);
m_pReadSlot->Put(SOCKET_EVENT_TYPE_CLOSE, pBuffSockToWrite, 0, 0);
goto ErrHand;//edit by xiny120 never make a read request after close 05-11-06 00:25:00
}
}
}
}
} while (1 == DoesItHaveMoreSequence);
SLock.Unlock();
goto ErrHand;
}
else
{
m_pEL->ErrLog(ERRLOC, "Odd operation.");
goto ErrHand; // bug!
}
}
RecvPoint:
// GetQueuedCompletionStatus detects a socket event whether IO is set or not by WSARecv(WSASend).
Flag = MSG_PARTIAL;
try
{
pBuffSock->OLExt.IOType = IO_TYPE_READ;
ResRecv = WSARecv(pBuffSock->Socket, &pBuffSock->BufferReadIO, 1, &IOSize, &Flag, (LPOVERLAPPED)&pBuffSock->OLExt, 0);
}
catch (...)
{
// suddenly, the BuffSock was closed and released by PreAllocator. Ignore...
goto ErrHand;
}
if (SOCKET_ERROR == ResRecv)
{
ErrorCode = WSAGetLastError();
if (WSA_IO_PENDING != ErrorCode)
{
if (WSAECONNRESET == ErrorCode || WSAECONNABORTED == ErrorCode
|| WSAESHUTDOWN == ErrorCode || WSAENETRESET == ErrorCode)
{
InterlockedIncrement((long *)&g_CloseByRead);
m_pReadSlot->Put(SOCKET_EVENT_TYPE_CLOSE, pBuffSock, 0, 0);
}
else
{
m_pEL->ErrLog(ERRLOC, "WSARecv is failed. Error Code = %d", ErrorCode);
InterlockedIncrement((long *)&g_CloseByRead);
m_pReadSlot->Put(SOCKET_EVENT_TYPE_CLOSE, pBuffSock, 0, 0);
}
}
}
ErrHand:
return;
} // IOWorker()
|
|
|
|
|
After I test for about 2 weeks,the server is quite stable now.I changed somewhere and modify ovelapped struct pIOCPNet member to the server pointer and manager the server object not deleted until all the pending IOWorkerDummy be stoped,add a member to tell the server to shutdown socket while all packet sended.(I don't know wether it's needed)
|
|
|
|
|
how can you close client socket ?? CloseEx.... looks like have problems....
|
|
|
|
|
I have a few issues with this article. I'm sorry that this comment appears a little harsh but there is just too much that is just plain wrong in the article to allow it to go unchallenged.
1) AcceptEx - As far as my tests have shown, there's no difference in the resource limits applied to WSAAccept or AcceptEx. With WSAAccept the failure occurs when you call the function because it's a synchronous call, with AcceptEx the failure is reported via the IOCP that is assigned to the socket that you're calling AcceptEx on. Both face the same non-paged pool limits. It might have been useful to present both styles of server so that you could prove your belief that AcceptEx doesn't suffer these problems. I have run tests with my IOCP framework's Accept and AcceptEx based servers and both can achieve 64,000+ concurent connections. Also, the failure isn't because the system can't keep up, it's because there's a finite limit of "non-paged memory" and each socket uses some (as do drivers, etc). When you use it all up you can't create any more sockets or perform most overlapped operations on them. See Network Programming for Microsoft Windows for more details of the limits that you might face when writing servers that need to service lots of connections.
3) Static memory - I think you need to define your terms here. What do you think the term "static memory" means? Preallocating the resources used by 65000 connections isn't really a good idea. First there's the start up time of the server to take into consideration. Second there's the effect that such a program has on other programs trying to run on the same machine. Third the server 'wastes' resources if it isn't always 100% loaded (ie when there's only 10000 connections we're wasting 55000 socket resources...) Fourth non-paged pool is a fixed sized per machine resource; allocating lots of it because you might need it later is a bad idea. Fifth your server can only run on a machine with enough memory to handle the preconfigured maximum number of connections... Personally I'd do it differently. I'd possibly preallocate some resources and then cache resources as they're released so that they can be reused. You can then tune the caching to take into account your expected usage.
4) Sliced data chunk - This is just wrong when you're talking about TCP connections (which are what the sample code creates). You may run into the problem stated when using large packets for UDP sockets but you're not. You can usually tune the UDP packet size if you need to.
5) Don't spawn many threads - This is the KEY point about using IOCP. It restricts the number of threads you need and it restricts the context switching that occurs. The whole point of overlapped IO is that you don't NEED to spawn more threads for your socket IO or for any IO that can use IOCP. For non IOCP enabled IO (such as database connections) it's probably best to use a thread pool rather than spawning a thread for each operation...
6) The uniqueness of socket - What? a SOCKET is an OPAQUE DATA TYPE. It's like a handle. You, as an application programmer need never know or worry about the value. If a socket closes "suddenly" you're told about it and the socket isn't actually closed until YOU close it. If the remote side of the connection closes their side then you'll likely be told about it (assuming you have a read pending, or you try to write to it). The socket that YOU have is valid until YOU close it. The OS isn't going to reuse the socket until you have closed it. Once you close it you shouldn't reuse the SOCKET because it's not yours anymore...
I think that's enough to be going on with for now. I have some comments on the code too but I always have comments on the code...
I would strongly suggest that anyone planning to base a server on this code read some of the other IOCP articles on here first. If dealing with lots (10000+) of concurrent connections is important to you then I suggest you read at least the scalability chapter of Network Programming for Microsoft Windows.
Discuss...
Len Holgate
www.jetbyte.com
The right code, right now.
|
|
|
|
|
You're right.
I thought they were minor issues (related with memory, data chunk for small buffred routers, uniqueness, ...) than the result the high performance sever runs.
And I didn't want to explain about them in very detail with my lacked English.
Your comment to this article may be the best reference for others.
Thanks.
-- modified at 9:37 Sunday 30th October, 2005
|
|
|
|
|
I agree, it's better to get something that works rather than something that is completely error free. I think it would be good for you to spend some time working on the article a bit to make it better. Perhaps, for example, show the trade off between allocating all of your memory in advance against allocating some in advance and some later. I find that doing these kind of things often help me to understand the problems better.
Len Holgate
www.jetbyte.com
The right code, right now.
|
|
|
|
|
I have tested both programs.The iocpnet program's performance is better.And the jetbyte's program use little system resource.When lots of incomming connections come together,the iocpnet doesn't refues connections but the jetbyte's do refuse.
|
|
|
|
|
|
Which version of the my servers did you use to test? The acceptex version? How did you configure it? What machine specification? How many concurrent connections? Define "better", etc.
Shall we review the coding practices next ?
Len Holgate
www.jetbyte.com
The right code, right now.
|
|
|
|
|
Not the acceptex version.Just the common version of your latest release.I start 100 threads to setup 10000 connections to the server.And offen be refused by the jetbyte server.The acceptEx version may of course be better,but I found it not developed later,so I havn't test yet.there is someting in iocpnet not dealed very well,such as shutdown socket when you dont wana send or receive data later and the iocpnet member of the overlapped struct not used,global IOCPNet objects make it impossible to setup two iocpnet object in one application,I changed some code and make it done.The jetbyte version is well done.I'm develping a server program maybe with lots of concurrent connections and lots of incomming connections in a short time.Since lots of client program was writen by others and don't maintain well the connections.When the client can't connect to the server,It report errors.I don't wanna this happen.Since the client was in the mobile phone and can't be updated.so I have to use a fast server.Some of my code use the jetbyte socket earyly,but the acceptEx version was not updated and cann't share the io threadpool and loginthread pool.What a pity!The jetbyte iocp modal is the mose stable iocp modal I'v ever test.
|
|
|
|
|
Did you tune the listen backlog? I think it defaults to just 5. This is probably the biggest cause of low socket acceptance performance. Also, are you running on a server platform? If not then an AcceptEx() server will probably always outperform a traditional Accept() server due to the limits on the listen backlog queue in the "client" versions of windows.
One other thing you may find out this code is that it doesn't seem to handle multiple sends and recvs on the same socket, this may or may not be an issue for you.
The AcceptEx() version of our code has been updated to our new framework but we're not giving that code away at the moment. If you would like to license it from us drop me an email.
Len Holgate
www.jetbyte.com
The right code, right now.
|
|
|
|
|
After I dune the backlog,it also refuse connections but the value it accept before it refuse increased.The AcceltEx is sure turned on.I'd like very much to get ur new versions since it is so stable.I have been use ur code for some time and I have a suggest if you can improve(or maybe improve)the Socket::Write(LPBYTE pData,int Len) to enable data len more than a buffersize,I change it to splite into many blocks in the functions.Since you are the author,I think you know how to do it best.
|
|
|
|
|
I'll upload some test servers built with the new code on my blog so you can test them. The new code already has the change to Write that you suggest.
Len Holgate
www.jetbyte.com
The right code, right now.
|
|
|
|
|
Couldn't find the test code even searched by google.
|
|
|
|
|
I didn't get a chance to upload it yesterday. Will do so today. Sorry, I was really busy.
Len Holgate
www.jetbyte.com
The right code, right now.
|
|
|
|
|
|
Run ID is the thread Number,Thread 0 Thread 1:1...
Each thread make up connections 100
Loop ..100
look at the result of your r01-echoserver.exe:
Client: Press any key to stop...
ErrorCode = 10061
Connect is failed. Run ID = 94, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 12, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 13, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 14, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 15, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 16, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 17, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 18, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 19, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 20, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 21, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 22, Loop = 2
ErrorCode = 10061
Connect is failed. Run ID = 23, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 24, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 25, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 26, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 27, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 28, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 29, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 30, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 31, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 32, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 33, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 34, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 35, Loop = 3
ErrorCode = 10061
Connect is failed. Run ID = 37, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 38, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 39, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 0, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 40, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 41, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 42, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 43, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 44, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 45, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 1, Loop = 5
ErrorCode = 10061
Connect is failed. Run ID = 2, Loop = 4
ErrorCode = 10061
Connect is failed. Run ID = 57, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 58, Loop = 1
ErrorCode = 10061
Connect is failed. Run ID = 59, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 60, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 61, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 62, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 63, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 64, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 65, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 66, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 67, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 68, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 69, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 70, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 71, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 72, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 73, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 74, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 75, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 36, Loop = 10
Connect is failed. Run ID = 36, Loop = 10
ErrorCode = 10061
Connect is failed. Run ID = 76, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 77, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 78, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 79, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 80, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 81, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 82, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 83, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 84, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 85, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 86, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 87, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 88, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 89, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 90, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 91, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 92, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 93, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 95, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 96, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 97, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 98, Loop = 0
ErrorCode = 10061
Connect is failed. Run ID = 99, Loop = 0
The IOCPNet never report error
Client: Press any key to stop...
|
|
|
|
|
test thread code like this:
#define USER_NUMBER 10000
#define THREAD_NUMBER 100
#define TEST_SERVER_IP "127.0.0.1"
int Connect(SOCKET *pSock, char *IP, unsigned short Port)
{
sockaddr_in SockAddr;
*pSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == *pSock)
{
return 0;
}
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(IP);
SockAddr.sin_port = htons(Port);
if (SOCKET_ERROR == connect(*pSock, (SOCKADDR*) &SockAddr, sizeof (SockAddr)))
{
DWORD ErrorCode = WSAGetLastError();
printf("ErrorCode = %d\n", ErrorCode);
return 0;
}
return 1;
} // Connect()
DWORD WINAPI NetworkingThread(void *pParam)
{
int RunID;
SOCKET *Sockets;
DWORD ErrorCode;
int iRes;
int ConnNum;
int Loop;
int Index=0;
ConnNum = USER_NUMBER / THREAD_NUMBER;
Sockets = (SOCKET *)malloc(sizeof (SOCKET) * ConnNum);
RunID = (int)pParam;
ZeroMemory(Sockets, sizeof (SOCKET) * ConnNum);
itoa(RunID % 10, Temp, 10);
for (Loop = 0; Loop < ConnNum; Loop++)
{
if (0 == Connect(&Sockets[Loop], TEST_SERVER_IP, TEST_SERVER_PORT))
{
printf("Connect is failed. Run ID = %d, Loop = %d\n", RunID, Loop);
ConnNum=Loop;
break;
}
}
if(ConnNum)
while (1 == InterlockedExchange((long *)&g_dRunning, g_dRunning))
{
Sleep(100);
}
ErrHand:
for (Loop = 0; Loop < ConnNum; Loop++)
{
if (0 != Sockets[Loop])
{
closesocket(Sockets[Loop]);
Sockets[Loop] = 0;
}
}
// exit(0);
free(Sockets);
return 0;
} // NetworkingThread()
-- modified at 20:21 Thursday 3rd November, 2005
|
|
|
|
|
Personally I wouldn't run the test on the same machine as the server (127.0.0.1) as you're probably seeing the effect of running a process with 100 threads all doing busy work on the same machine.
What is probably happening is this: The server from this article posts how ever many thousand AcceptEx calls when it starts up. My server posts a configurable number and then reposts as each accept completes. When you run this client on the same machine you probably max out the CPU on the machine and the server doesn't get to process the accepts so doesnt post any more and so runs out of sockets that are pending for accept. In my opinion this isn't a realistic test because in a real situation it's unlikely that you would run the server on a machine that is going to have other processses using up 100% cpu.
Run the client on another machine and see how things work then.
Len Holgate
www.jetbyte.com
The right code, right now.
|
|
|
|
|
How did you run the server? What did you specify as the listen backlog? Did you run the server on the same machine as the client? How many processors in the machine running the server? Etc.
Len Holgate
www.jetbyte.com
The right code, right now.
|
|
|
|
|
The result u should got if u setup the test.
|
|
|
|
|
Hi, testosterone IOCP guys, shall I bring the ruler for measurement?
//Spinoza
|
|
|
|
|
when I use OIOCPNet::CloseSocketExternal to close the client socket ,the OIOCPNet::m_ActiveConnectionNum will less than zero!!!!!!!!!!!
|
|
|
|
|
Sorry.
I thinks of I fixed CloseSocket also called by CloseSocketExternal. (and sent an article update request)
But if the problem doesn't be fixed, let me know it again, please.
Thanks.
|
|
|
|
|
void MainLogic(OIOCPNet *pIOCPNet, DWORD SocketUnique,
OBufferedSocket *pBuffSock, BYTE *pReadData, DWORD ReadSize)
{
if(!authentication)
{
pIOCPNet->CloseSocketExternal(SocketUnique,pBuffSock,0,0);//??like this??
}
pIOCPNet->WriteData(SocketUnique, pBuffSock,
pReadData, ReadSize); // echo.
} // MainLogic()
Thanks for your help!!
|
|
|
|
|