Sockets program question(cpu loading)

Started by
7 comments, last by Gizz 19 years, 8 months ago
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"); }
Advertisement
1) Buy a profiler.
2) Install said profiler.
3) Run program with said profiler.
4) Listen to what the profiler tells you.
enum Bool { True, False, FileNotFound };
There is no need to post everything.

First off, does the thread terminate properly?

Kuphryn
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]
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.
-=[ J ]=-I always forget to change the tagline.
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:
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

This topic is closed to new replies.

Advertisement