Sockets program question(cpu loading)
Hi guys,im wondering why is this code making the cpu loading so much?anyone know how could I down the cpu loading?it uses almost 90% in all machines.Thanks!Code:
int startupServerForListening(unsigned short port);
void shutdownServer(int socket);
HANDLE threadHandle;
HANDLE mutexHandle;
FD_SET masterSet;
bool gQuitFlag = false;
void acceptingThreadProcedure(int* serverSocket) {
// copy my socket over to a local variable
int mySocket = *serverSocket;
// run forever
for (;;) {
// accept a client like normal
unsigned int clientSocket = accept(mySocket, 0, 0);
// make sure things are ok
if (clientSocket == SOCKET_ERROR) {
// just stop of we received any errors
printf("Accept Failed!\n");
// signal to quit the application
gQuitFlag = true;
// and quit this thread
return;
} else {
// lock the mutex
WaitForSingleObject(mutexHandle, INFINITE);
// add this socket to the master set using our FD_SET() macro
FD_SET(clientSocket, &masterSet);
// unlock the mutex
ReleaseMutex(mutexHandle);
// a quick message
printf("----------------------\n");
printf("client on %d connected\n", clientSocket);
}
}
}
void main() {
// Startup our network as usual.
// the socket my server will use for listening
int serverSocket;
// startup my network utilities with my handy functions
serverSocket = startupServerForListening(9001);
// check for errors
if (serverSocket == -1) {
printf("Network Startup Failed!\nProgram Terminating\n");
return;
}
// create the mutex
mutexHandle = CreateMutex(NULL, false, NULL);
if (mutexHandle == NULL) {
printf("Error creating mutex\n");
shutdownServer(serverSocket);
return;
}
// create the thread
int threadId;
threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)acceptingThreadProcedure, &serverSocket, 0, (LPDWORD)&threadId);
if (threadHandle == NULL) {
printf("Could not start acceptance thread\n");
shutdownServer(serverSocket);
return;
}
Sleep(100);
FD_ZERO(&masterSet);
// the main loop ... run forever
for (;;) {
if (gQuitFlag) {
break;
}
WaitForSingleObject(mutexHandle, INFINITE);
// make the polling set and copy everything from masterSet
FD_SET pollingSet = masterSet;
// unlock the mutex
ReleaseMutex(mutexHandle);
// check if our set is empty
if (pollingSet.fd_count == 0) {
continue;
}
// the wait time
timeval waitTime;
waitTime.tv_sec = 0;
waitTime.tv_usec = 0;
// and select(). select from the polling set using fd_count as the number of sockets. We do not have a
// write set nor an errors set, so just pass NULL for them.
int result = select(pollingSet.fd_count, &pollingSet, NULL, NULL, &waitTime);
// check for no sockets with data
if (result == 0) {
// no sockets have data
continue;
}
// check for errors
if (result == SOCKET_ERROR) {
printf("Error in select()\n");
continue;
}
// for every socket in my polling set
for (unsigned int i = 0; i < pollingSet.fd_count; i++) {
// We can access the socket list directly using the fd_array member of the FD_SET
unsigned int clientSocket = pollingSet.fd_array;
// We will be using the same variable length data system that we implemented in tutorial #4.
// So we need a few variables to facilitate the communication.
// the number of bytes we received
int nBytes;
// a buffer to hold my data
#define MAX_MESSAGE_SIZE 1000
char buffer[MAX_MESSAGE_SIZE];
// the size of the message that is being sent
unsigned long messageSize;
// receive the message size first
nBytes = recv(clientSocket, (char*)&messageSize, sizeof(messageSize), 0);
// check for errors
if (nBytes == SOCKET_ERROR) {
int error = WSAGetLastError();
// handle the dropped connection
if (error == WSAECONNRESET) {
// lock our mutex
WaitForSingleObject(mutexHandle, INFINITE);
// remove the socket from our master set
FD_CLR(clientSocket, &masterSet);
// unlock our mutex
ReleaseMutex(mutexHandle);
// close the socket on our side, so our computer cleans up properly
closesocket(clientSocket);
// a quick message
printf("client on %d disconnected\n", clientSocket);
// move on to the next client
continue;
} else {
// we failed, but it wasn't an error we were expecting ... so kill the server
printf("Recv Failed!\n");
gQuitFlag = true;
break;
}
}
if (nBytes == 0) {
// lock our mutex
WaitForSingleObject(mutexHandle, INFINITE);
// remove the socket from our master set
FD_CLR(clientSocket, &masterSet);
// unlock our mutex
ReleaseMutex(mutexHandle);
// close the socket on our side, so our computer cleans up properly
closesocket(clientSocket);
// a quick message
printf("client on %d has finished the connection\n", clientSocket);
printf("----------------------------------------\n");
// move on to the next client
continue;
}
// convert the message size to host ordering
messageSize = ntohl(messageSize);
// receive the reset of the message
nBytes = recv(clientSocket, buffer, messageSize, 0);
// check for error
if (nBytes == SOCKET_ERROR) {
printf("Recv Failed!\n");
gQuitFlag = true;
break;
}
ofstream q("file.txt");
q<<buffer;
}
}
// cleanup
shutdownServer(serverSocket);
printf("Press Enter to Exit ...\n");
getchar();
}
// -----------------------------------------------------------------------------------
// startupServerForListening() - a function to startup winsock, and open a socket for listening
int startupServerForListening(unsigned short port) {
// an error code we will use to get more information about our errors
int error;
// the winsock data structure
WSAData wsaData;
// startup winsock
if ((error = WSAStartup(MAKEWORD(2, 2), &wsaData)) == SOCKET_ERROR) {
printf("Could Not Start Up Winsock!\n");
return -1;
}
// create my socket
int mySocket = socket(AF_INET, SOCK_STREAM, 0);
// make sure nothing bad happened
if (mySocket == SOCKET_ERROR) {
printf("Error Opening Socket!\n");
return -1;
}
// the address structure
struct sockaddr_in server;
// fill the address structure with appropriate data
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
// and now bind my socket
if (bind(mySocket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
printf("Bind Failed!\n");
closesocket(mySocket);
return -1;
}
// mark my socket for listening
if (listen(mySocket, 5) == SOCKET_ERROR) {
printf("Listen Failed!\n");
closesocket(mySocket);
return -1;
}
printf("Server Started\n");
return mySocket;
}
// -----------------------------------------------------------------------------------
// shutdownServer() - a function to shutdown a socket and clean up winsock
void shutdownServer(int socket) {
// kill my thread and my handle
WaitForSingleObject(threadHandle, INFINITE);
CloseHandle(threadHandle);
CloseHandle(mutexHandle);
// close our socket
closesocket(socket);
// shut down winsock
WSACleanup();
printf("Server Shutdown\n");
}
1) Buy a profiler.
2) Install said profiler.
3) Run program with said profiler.
4) Listen to what the profiler tells you.
2) Install said profiler.
3) Run program with said profiler.
4) Listen to what the profiler tells you.
Cut out as much code as possible, and see what part of the code makes the CPU load so much.
I guess it should be the main loop,the code is:
for (;;) {
// accept a client like normal
unsigned int clientSocket = accept(mySocket, 0, 0);
// make sure things are ok
if (clientSocket == SOCKET_ERROR) {
// just stop of we received any errors
printf("Accept Failed!\n");
// signal to quit the application
gQuitFlag = true;
// and quit this thread
return;
} else {
// lock the mutex
WaitForSingleObject(mutexHandle, INFINITE);
// add this socket to the master set using our FD_SET() macro
FD_SET(clientSocket, &masterSet);
// unlock the mutex
ReleaseMutex(mutexHandle);
// a quick message
printf("----------------------\n");
printf("client on %d connected\n", clientSocket);
}
}
Or,it could be for this timer?(this is another loop)
timeval waitTime;
waitTime.tv_sec = 0;
waitTime.tv_usec = 0;
// and select(). select from the polling set using fd_count as the number of sockets. We do not have a
// write set nor an errors set, so just pass NULL for them.
int result = select(pollingSet.fd_count, &pollingSet, NULL, NULL, &waitTime)
the server and client works well without any error.Thanks!
[Edited by - cofruben on August 26, 2004 11:51:03 AM]
for (;;) {
// accept a client like normal
unsigned int clientSocket = accept(mySocket, 0, 0);
// make sure things are ok
if (clientSocket == SOCKET_ERROR) {
// just stop of we received any errors
printf("Accept Failed!\n");
// signal to quit the application
gQuitFlag = true;
// and quit this thread
return;
} else {
// lock the mutex
WaitForSingleObject(mutexHandle, INFINITE);
// add this socket to the master set using our FD_SET() macro
FD_SET(clientSocket, &masterSet);
// unlock the mutex
ReleaseMutex(mutexHandle);
// a quick message
printf("----------------------\n");
printf("client on %d connected\n", clientSocket);
}
}
Or,it could be for this timer?(this is another loop)
timeval waitTime;
waitTime.tv_sec = 0;
waitTime.tv_usec = 0;
// and select(). select from the polling set using fd_count as the number of sockets. We do not have a
// write set nor an errors set, so just pass NULL for them.
int result = select(pollingSet.fd_count, &pollingSet, NULL, NULL, &waitTime)
the server and client works well without any error.Thanks!
[Edited by - cofruben on August 26, 2004 11:51:03 AM]
It isn't the first loop, since accept() blocks until the connection is accepted, and is no time consuming.
I think it is your message-processing loop. You are polling the buffers to see if a message has arrived. I prefer to spawn a thread to attend each connection, but if you don't want, you can sleep when no message is your "polling set".
for (;;) {
if (gQuitFlag) {
break;
}
WaitForSingleObject(mutexHandle, INFINITE);
...
See, you want to sleep both when no message has arrived, and also when there are still no connections, so before getting the mutex, write Sleep(100) (I say this because you have a nasty 'continue' below, which causes the loop to restart if there are still no connections).
This is a very bad solution. I prefer blocking my app until the IO operation happens, so I use a thread for each connection (though for a heavily-loaded server this may not be the optimal solution, I don't know).
Overall, try to better structure your code. I'm sorry but I can't help more. Hope this helps in some way.
I think it is your message-processing loop. You are polling the buffers to see if a message has arrived. I prefer to spawn a thread to attend each connection, but if you don't want, you can sleep when no message is your "polling set".
for (;;) {
if (gQuitFlag) {
break;
}
WaitForSingleObject(mutexHandle, INFINITE);
...
See, you want to sleep both when no message has arrived, and also when there are still no connections, so before getting the mutex, write Sleep(100) (I say this because you have a nasty 'continue' below, which causes the loop to restart if there are still no connections).
This is a very bad solution. I prefer blocking my app until the IO operation happens, so I use a thread for each connection (though for a heavily-loaded server this may not be the optimal solution, I don't know).
Overall, try to better structure your code. I'm sorry but I can't help more. Hope this helps in some way.
i guess jjmontes is right, the
for (;;) {
...
}
will eat most of your cpu time.
some ideas i got when looking at your code:
1. you don't need a separate thread for accept(); you can use the above loop in main() to call that code.
2. if you get rid of the thread you can get rid of all the mutexes and synchronization stuff
3. the loop then goes like this:
sometimes less is more :)
for (;;) {
...
}
will eat most of your cpu time.
some ideas i got when looking at your code:
1. you don't need a separate thread for accept(); you can use the above loop in main() to call that code.
2. if you get rid of the thread you can get rid of all the mutexes and synchronization stuff
3. the loop then goes like this:
int main(){ // create server socket int srv=create_serversocket(); // add server socket to the FD-set (for select()) FD_SET(&readfds, srv); while (1) { // call select() int s=select(maxfd, &readfds, ...); // walk through all sockets for (i=0; i<maxfd; i++) { // is it the server socket? then call accept() if (i==srv) { cli=do_accept(srv); // add the new client socket to the FD-set FD_SET(&readfds, cli); } // otherwise read from a client connection else { do_read(i); } } }
sometimes less is more :)
thank you two a lot,the sleep thing worked for me well,im going to try that code too,thanks!!
You might want to change your mutex for a critical section. Using a mutex imply a user space to kernel space transition which amount to about a thousand cpu cycle roundtrip (see Programming Server-Side Applications for Microsoft Windows 2000 for reference).
But be warned that critical section are tied to one process and thus can't be used to do inter-process synchronization (which doesn't apply to your case anyway since you seem to be in a single process).
Gizz
But be warned that critical section are tied to one process and thus can't be used to do inter-process synchronization (which doesn't apply to your case anyway since you seem to be in a single process).
Gizz
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement