Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Async Chat server/client suggestions and hints.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 netpumber   Members   -  Reputation: 100

Like
0Likes
Like

Posted 22 December 2011 - 11:50 AM

Hello.

So a month now im searching in net different methods to create a chat client/server app.
Clients will connect to the server and the server will send the message of each client to the rest.
I use C and Visual studio 10 and finally i decided to use the async method.
My app will be a simple console application so i will use WSAEventSelect instead of WSAAsyncSelect.

I have found only this tutorial on net talking about this.

Also i read and for IOCP but my knowledge is not enough for something like this.

I ask you to tell me if you find my decision correct and if you have any tutorial or post on mind that can help me. Please let me know.

Also any hint or suggestion is welcomed.

Thanks in advance.

Sponsor:

#2 frob   Moderators   -  Reputation: 22236

Like
0Likes
Like

Posted 22 December 2011 - 11:59 AM

It seems like several entries in the FAQ would cover this. Have you read the FAQ thoroughly and read the documents it links to?


Chat is no different than any other message; it happens to have text that you display, but that kind of network message is no different than a message about updating units or updating player stats or transmitting a VoIP message. It is just a block of data meant for direct display to the human.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#3 netpumber   Members   -  Reputation: 100

Like
0Likes
Like

Posted 22 December 2011 - 12:51 PM

Yeah ok i ve read the FAQ but it talks mostly for select() method as i saw.
The truth is that i have try the select method but there was a problem with the message send time.

Here is my code for my select() try.

Server:

....
	// Listening
	//iMode = 1; // If iMode!=0, non-blocking mode is enabled.
	listen(ListeningSocket,5);
	//ioctlsocket(ListeningSocket,FIONBIO,&iMode); // Enable the non-locking mode.

	// Clear the two fd sets
	FD_ZERO(&fdread);
	FD_ZERO(&BackUpfdread);
	FD_ZERO(&fdwrite);
	FD_ZERO(&BackUpfdwrite);

	// Asign the ListeningSocket with fdread.
	FD_SET(ListeningSocket,&fdread);
	FD_SET(ListeningSocket,&fdwrite);

	// Set as maxDescriptor ListeningSocket.
	maxDescriptor = ListeningSocket;

	// Setup timer.
	timeout.tv_sec = 2;
	timeout.tv_usec = 5000;

	// Main loop starts here.

	for(; ; )
	{
		// Keep a backup of FD set cause select() erases it, if there's nothing to do.
		BackUpfdread = fdread;
		BackUpfdwrite = fdwrite;
		selectResults = select(maxDescriptor+1,&BackUpfdread,&BackUpfdwrite,NULL,&timeout);

		if(selectResults == -1)
		{
			printf("Select() error");
			WSACleanup();
			return 0;
		}


		// Check the fdread set for alive connections
		for(i=0;i<=maxDescriptor;i++)
		{
			if(FD_ISSET(i,&BackUpfdread)) 
			{
				if(i == ListeningSocket) // That means we have a NEW CONNECTION and must hadle it. 
				{
					ClientAddrSize = sizeof(ClientAddr);
					AcceptSocket = accept(ListeningSocket,(SOCKADDR *)&ClientAddr,&ClientAddrSize);

					if(AcceptSocket == -1)
					{
						printf("Winsock error - Unable to accept socket");
						WSACleanup();
						return 0;
					}

					// Add the newest socket in the fdread set.
					FD_SET(AcceptSocket,&fdread);
					FD_SET(AcceptSocket,&fdwrite);
					// Keep track of the maxDescriptor.
					if(AcceptSocket > maxDescriptor)
					{
						maxDescriptor = AcceptSocket;
					}

					// Receiving the username from the new client.
					memset(username,0,sizeof(username));
					recv(AcceptSocket,username,sizeof(username),0);

					printf("New connection (username: %s) from %s on socket %d\n", username, inet_ntoa(ClientAddr.sin_addr), AcceptSocket);

					// Send Welcome Message.
					send(AcceptSocket,msg,sizeof(msg),0);
				
				}else{ // That means that the socket (i) isn't from a new connection and has something sent.

					RecvBytes = recv(i, RecvBuff, sizeof(RecvBuff)-1, 0);

					if(RecvBytes == -1)
					{
						printf("Winsock error - Cannot receive data from client");
						WSACleanup();
						return 0;
					}

					if(RecvBytes == 0)
					{
						printf("Socket %d hung up\n", i);
						// Shutdown Socket
						shutdown(i,SD_RECEIVE);
						// Clear fdread.
						FD_CLR(i, &fdread);
					}

					if(RecvBytes > 0)
					{
						printf("Message Send.\n");
						printf("Message was: %s\n",RecvBuff);

						for(k=0;k<=maxDescriptor;k++)
						{
							if(FD_ISSET(k,&BackUpfdwrite))
							{
								memset(SentBuff,0,sizeof(SentBuff));
								strcpy(SentBuff,RecvBuff);
								SentBytes = send(k,SentBuff,sizeof(SentBuff),0);
							}
												
						}

					}
				}
			}
		}

	} // Main loop ends here.
...


Client:
....
				// Initialize Winshock 2.2
				WSAStartup(MAKEWORD(2,2),&wsaData);

				// Create a new socket to make a client connection.
				ConnectSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

				// Initialize Servers SOCKADDR_IN
				ServerAddr.sin_family = AF_INET;
				ServerAddr.sin_port = htons(port);
				ServerAddr.sin_addr.s_addr = inet_addr(server_address);

				// Clear the fd sets
				FD_ZERO(&fdread);
				FD_ZERO(&BackUpfdread);
				FD_ZERO(&fdwrite);
				FD_ZERO(&BackUpfdwrite);

				// Asign the ListeningSocket with fdread and fdwrite.
				FD_SET(ConnectSocket,&fdread);
				FD_SET(ConnectSocket,&fdwrite);

				// Set as maxDescriptor ListeningSocket.
				maxDescriptor = ConnectSocket;

				// Setup timer.
				timer.tv_sec = 2;
				timer.tv_usec = 5000;

				//iMode = 1; // If iMode!=0, non-blocking mode is enabled.
				//ioctlsocket(ConnectSocket,FIONBIO,&iMode); // Enable the non-locking mode.

				// Make a connection to the server with socket s.
				connect(ConnectSocket, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)); 

				// Send the username to server.
				send(ConnectSocket,username,strlen(username),0);

				// Receive Welcome Message From Server (If any..)
				RecvBytes = recv(ConnectSocket,RecvBuff,sizeof(RecvBuff),0);

				if(RecvBytes > 0)
				{
			       printf("%s",RecvBuff);   
			       // Cleaning the Receive Buffer 
			       memset(RecvBuff,0,sizeof(RecvBuff));
			     }  

				// Main loop starts here
				for(; ; )
				{

			       // Copy the fdread into BackUpfdread and fdwrite to BackUpfdwrite.
			       BackUpfdread = fdread;
			       BackUpfdwrite = fdwrite;

			       SelectResults = select(maxDescriptor+1,&BackUpfdread,&BackUpfdwrite,NULL,&timer);
			       
			       if(SelectResults == -1)
			       {
				       perror("Client-select() error!\n");
				       exit(1);
			       }

			       //printf("Client-select is OK\n");

			       //Check if we have some data to read.
			  	if (FD_ISSET(ConnectSocket, &BackUpfdread))
			  	{
					RecvBytes = recv(ConnectSocket, RecvBuff, sizeof(RecvBuff), 0);
					if(RecvBytes > 0)
					{
				  	printf("%s\n",RecvBuff);
				  	// Cleaning the Receive Buffer
				  	memset(RecvBuff,0,sizeof(RecvBuff));
					}
			  	}

			  	memset(SentBuff, 0, sizeof(SentBuff));
			  	printf("Write: ");
			  	gets_s(SentBuff, sizeof(SentBuff));

			  	//Check if we have some data to write.
			  	if (FD_ISSET(ConnectSocket, &BackUpfdwrite))
			  	{
					SentBytes = send(ConnectSocket, SentBuff,sizeof(SentBuff),0);
					// Cleaning the Sent Buffer
					memset(SentBuff,0,sizeof(SentBuff));
			  	}

			  	

				} // Main loop ends here
....



and here is the image that shows the message transfer delay.

Posted Image

After these problems i decided to use the WSAEventSelect with event creation and blah blah as the tutorial posted before says..

#4 hplus0603   Moderators   -  Reputation: 5528

Like
2Likes
Like

Posted 22 December 2011 - 07:08 PM

    // Setup timer.
	timeout.tv_sec = 2;
	timeout.tv_usec = 5000;


This timeout specifies 2.005 seconds -- two seconds, and five thousand microseconds. Perhaps this is what you intend, but I think it's not.
Generally, when polling the network together with a game or event loop, you want to set tv_sec and tv_usec both to 0.

        for(i=0;i<=maxDescriptor;i++)
		{
			if(FD_ISSET(i,&BackUpfdread)) 


This doesn't work well at all in Windows. sockets are handles, which can have very high values. "maxDescriptor" is ignored on input. You should test the values you know you have (the listening socket, and each client socket) rather than "all integers." You're basically testing ALMOST ALL INTEGERS to see if one of them happens to match a handle value stored in the FD_SET. That is one cause of performance problems.

                    // Receiving the username from the new client.
					memset(username,0,sizeof(username));
					recv(AcceptSocket,username,sizeof(username),0);


Someone can block your game forever by doing telnet to your server, and then not sending a username. Never recv from a socket unless select() tells you it won't block.

                    RecvBytes = recv(i, RecvBuff, sizeof(RecvBuff)-1, 0);


See above -- "i" is generally not a valid socket handle value.

After these problems i decided to use the WSAEventSelect with event creation and blah blah as the tutorial posted before says..


WSAEventSelect is only slightly less bad than WSAAsyncSelect. Use select(), or use OVERLAPPED I/O on sockets as handles.
Note that, apart from scanning all integers, other performance problems with your test may be that there is not enough CPU to handle all the clients+server you're running, so Windows will time slice, and also you're not using TCP_NODELAY, so sends will be delayed by several hundred milliseconds.
enum Bool { True, False, FileNotFound };

#5 netpumber   Members   -  Reputation: 100

Like
0Likes
Like

Posted 23 December 2011 - 06:05 AM

Thanks a lot for your answer hplus0603 .

First of all i think that the second problem you referred to, will be solved using a struct that will save the socket number of each client and in the for loop i will use these numbers.

As for the username sending i will find another way to do this.

Finally i want you to tell me why to use select() and not WSAEventSelect method.
As i read on net the first one uses more CPU than the other.


#6 hplus0603   Moderators   -  Reputation: 5528

Like
0Likes
Like

Posted 23 December 2011 - 12:08 PM

Finally i want you to tell me why to use select() and not WSAEventSelect method.
As i read on net the first one uses more CPU than the other.


WASEventSelect() has an inherent race condition that is very hard to work around. If you read about it on MSDN, they talk about it, but don't actually explain the systems programming aspects. And yet, it's not very scalable -- the NT kernel can wait on at most 64 events at the same time (using MsgWaitForMultipleObjectsEx()).

If you want simple to code, use select() -- it will work fine for dozens of connections.

If you want high performance, use OVERLAPPED I/O on sockets with I/O completion ports -- or use boost::asio, which puts a slightly nicer interface on top of that, plus is portable across operating systems.
enum Bool { True, False, FileNotFound };

#7 wood_brian   Banned   -  Reputation: 197

Like
0Likes
Like

Posted 23 December 2011 - 03:42 PM


        for(i=0;i<=maxDescriptor;i++)
		{
			if(FD_ISSET(i,&BackUpfdread)) 


This doesn't work well at all in Windows. sockets are handles, which can have very high values. "maxDescriptor" is ignored on input. You should test the values you know you have (the listening socket, and each client socket) rather than "all integers." You're basically testing ALMOST ALL INTEGERS to see if one of them happens to match a handle value stored in the FD_SET. That is one cause of performance problems.


I had something like that and changed it to as follows. I didn't do any measurements, but thought there was a noticeable improvement in the performance from the change. I count down rather than starting at zero and counting up. Also the code with the selrc is used to shorten this potentially long loop. selrc is the return code from select. After addressing all of the events, we can skip the rest of the loop.

for (int32_t sock = fdmax; sock > 0; --sock) {
  if (FD_ISSET(sock, &read_fds)) {
    if (mediateRequest(sock)) {
      FD_SET(cmwSendbuf.sock_, &masterwrite);
    } else {
      closeSocket(sock);
      FD_CLR(sock, &master);
    }
    if (0 == --selrc) break;
  }
}


Brian Wood
Ebenezer Enterprises
http://webEbenezer.net

#8 wood_brian   Banned   -  Reputation: 197

Like
0Likes
Like

Posted 23 December 2011 - 03:55 PM


Finally i want you to tell me why to use select() and not WSAEventSelect method.
As i read on net the first one uses more CPU than the other.


WASEventSelect() has an inherent race condition that is very hard to work around. If you read about it on MSDN, they talk about it, but don't actually explain the systems programming aspects. And yet, it's not very scalable -- the NT kernel can wait on at most 64 events at the same time (using MsgWaitForMultipleObjectsEx()).

If you want simple to code, use select() -- it will work fine for dozens of connections.


I like select's portability and not having to depend on a large library which itself depends on a number of other libraries. (I don't use select in the C++ Middleware Writer, but portability isn't an issue there.)

Brian Wood
Ebenezer Enterprises
http://webEbenezer.net

#9 frob   Moderators   -  Reputation: 22236

Like
1Likes
Like

Posted 24 December 2011 - 02:57 AM


        for(i=0;i<=maxDescriptor;i++)
		{
			if(FD_ISSET(i,&BackUpfdread)) 

This doesn't work well at all in Windows. sockets are handles, which can have very high values. "maxDescriptor" is ignored on input. You should test the values you know you have (the listening socket, and each client socket) rather than "all integers." You're basically testing ALMOST ALL INTEGERS to see if one of them happens to match a handle value stored in the FD_SET. That is one cause of performance problems.

I had something like that and changed it to as follows. I didn't do any measurements, but thought there was a noticeable improvement in the performance from the change.
for (int32_t sock = fdmax; sock > 0; --sock) {
  if (FD_ISSET(sock, &read_fds)) {

That suffers from exactly the same problem.

You are not iterating over your handles in either examples.

Instead you are iterating over potentially billions of integers where by brute force it will eventually stumble over your handle.


Keep a separate list of handles and only iterate over those. For example, you may have:

typedef std::vector<int32_t> HandleCollection;
...
HandleCollection openHandles;
...

// add an incoming connection
AcceptSocket = accept(ListeningSocket,(SOCKADDR *)&ClientAddr,&ClientAddrSize);
openHandles.push_back(AcceptSocket);
...
for(HandleCollection::iterator it = openHandles.begin(); it!=openhandles.end(); ++it;)
{ 
  if (FD_ISSET(*it, &read_fds)) {
...
This will reduce it from attempting to check against potentially billions of non-handles to instead just checking against the small number of actual handles you know to be open.

In practice you will likely want to store more than just an integer. Eventually you will want a structure or class with additional information about each client, but that is a future exercise.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#10 netpumber   Members   -  Reputation: 100

Like
0Likes
Like

Posted 24 December 2011 - 06:43 AM

Hello again.

After our conversation here i decide to give a try once again with select method.
Here is the new code.
I put 0 in timeout and also i use an array with sockets to avoid looping between all these integers.

Server:

#include <WinSock2.h>
#include <stdio.h>
#include <time.h>



main()
{

	SOCKET			ListeningSocket;
	SOCKET			AcceptSocket;

	SOCKADDR_IN		ServerAddr;
	SOCKADDR_IN		ClientAddr;

	WSADATA			wsaData;

	const unsigned short PORT = 4444;

	FD_SET			fdread;
	FD_SET			BackUpfdread;
	FD_SET			fdwrite;
	FD_SET			BackUpfdwrite;

	int				maxDescriptor;
	SOCKET			SocketArray[20];
	int				index = 0;
	int				selectResults;
	int				i,k;
	int				clientAddrSize;
	int				RecvBytes;
	int				SentBytes;

	char			SentBuff[500];
	char			RecvBuff[500];

	struct	timeval timeout;

	// Initialize Winsock2.2
	WSAStartup(MAKEWORD(2,2),&wsaData);

	// Initialize Listening Socket
	ListeningSocket = socket(AF_INET,SOCK_STREAM,0);

	// Initialize ServerAddr
	ServerAddr.sin_family = AF_INET;
	ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	ServerAddr.sin_port = htons(PORT);

	// Bind the ServerAddr with ListeningSocket
	bind(ListeningSocket,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr));

	// Listening Socket
	listen(ListeningSocket,5);

	FD_ZERO(&fdread);
	FD_ZERO(&BackUpfdread);
	FD_ZERO(&fdwrite);
	FD_ZERO(&BackUpfdwrite);

	// Asign ListeningSocket at fdread
	FD_SET(ListeningSocket,&fdread);

	maxDescriptor = ListeningSocket;

	SocketArray[index] = ListeningSocket;
	index++;

	timeout.tv_sec = 0;
	timeout.tv_usec = 0;

	// Main loop starts here
	for(; ;)
	{
		
		BackUpfdread = fdread;
		BackUpfdwrite = fdwrite;
		selectResults = select(maxDescriptor+1,&BackUpfdread,&BackUpfdwrite,NULL,&timeout);
		//printf("server select() OK\n");

		if(selectResults == -1)
		{
			printf("Select() error");
			WSACleanup();
			return 0;
		}


		for(i=0;i<=index-1;i++)
		{
			//printf("%d\n",SocketArray[i]);
			if(FD_ISSET(SocketArray[i],&BackUpfdread))
			{
				if(SocketArray[i] == ListeningSocket) // we have a new connection
				{
					clientAddrSize = sizeof(ClientAddr);
					AcceptSocket = accept(ListeningSocket,(SOCKADDR *)&ClientAddr,&clientAddrSize);

					// Add the newest accepted socket to the fdread and fdwrite sets.
					FD_SET(AcceptSocket,&fdread);
					FD_SET(AcceptSocket,&fdwrite);

					// Add the newest accepted socket into SocketArray
					SocketArray[index] = AcceptSocket;
					index++;

					// keep track of the maxDescriptor.
					if(AcceptSocket > maxDescriptor)
					{
						maxDescriptor = AcceptSocket;
					}

					printf("New connection from %s on socket %d\n", inet_ntoa(ClientAddr.sin_addr), AcceptSocket);

				}else{ // That means that the socket is not from a new conection and has something sent.

					memset(RecvBuff,0,sizeof(RecvBuff));
					RecvBytes = recv(SocketArray[i], RecvBuff, sizeof(RecvBuff)-1, 0);

					if(RecvBytes > 0) // Some data received.
					{

						printf("Message Send.\n");
						printf("Message was: %s\n",RecvBuff);

						for(k=0;k<=index-1;k++)
						{
							if(FD_ISSET(SocketArray[k],&BackUpfdwrite))
							{
								if(SocketArray[k] != ListeningSocket && SocketArray[k] != SocketArray[i])
								{
									memset(SentBuff,0,sizeof(SentBuff));
									strcpy(SentBuff,RecvBuff);
									SentBytes = send(SocketArray[k],SentBuff,sizeof(SentBuff),0);

								}

							}
						}

					}

				}

			}
		}


	}// Main loop ends here


}


Client:

#include <WinSock2.h>
#include <stdio.h>
#include <time.h>



main()
{

	SOCKET			ConnectSocket;
	SOCKET			SocketArray[20];

	SOCKADDR_IN		ServerAddr;

	WSADATA			wsaData;

	FD_SET			fdwrite;
	FD_SET			fdread;
	FD_SET			BackUpfdread;
	FD_SET			BackUpfdwrite;

	char			server_address[20] = "192.168.1.4";
	char			SentBuff[500];
	char			RecvBuff[500];

	const unsigned short PORT = 4444;

	int				maxDescriptor;
	int				index = 0;
	int				SelectResults;
	int				i;
	int				RecvBytes;
	int				SentBytes;

	struct timeval	timeout;


	// Initialize Winsock 2.2
	WSAStartup(MAKEWORD(2,2),&wsaData);

	// Initialize ServerAddr
	ServerAddr.sin_family = AF_INET;
	ServerAddr.sin_addr.s_addr = inet_addr(server_address);
	ServerAddr.sin_port = htons(PORT);

	// Create a new socket to make a client connection.
	ConnectSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

	// Clear the fd sets
	FD_ZERO(&fdread);
	FD_ZERO(&BackUpfdread);
	FD_ZERO(&fdwrite);
	FD_ZERO(&BackUpfdwrite);

	// Asign ConnectSocket into fdread and fdwrite.
	FD_SET(ConnectSocket,&fdread);
	FD_SET(ConnectSocket,&fdwrite);

	// Set timer
	timeout.tv_sec = 0;
	timeout.tv_usec = 0;

	maxDescriptor = ConnectSocket;
	SocketArray[index] = ConnectSocket;
	index++;

	// Make a connection to the server with socket s.
	if(connect(ConnectSocket, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
	{
		printf("Couldn't connect to the server\n");
	}

	// Main loop starts here
	for(; ;)
	{
		BackUpfdread = fdread;
		BackUpfdwrite = fdwrite;

		memset(SentBuff, 0, sizeof(SentBuff));
		printf("Write: ");
		gets_s(SentBuff, sizeof(SentBuff));

		SelectResults = select(maxDescriptor+1,&BackUpfdread,&BackUpfdwrite,NULL,&timeout);

		for(i=0;i<=index-1;i++)
		{
			// Something to read from server.
			if(FD_ISSET(SocketArray[i],&BackUpfdread) && SocketArray[i] == ConnectSocket) 
			{
				RecvBytes = recv(SocketArray[i], RecvBuff, sizeof(RecvBuff), 0);

				if(RecvBytes > 0)
				{
					printf("%s\n",RecvBuff);   
					// Cleaning the Receive Buffer 
					memset(RecvBuff,0,sizeof(RecvBuff));
				}

			}

			// Something to write.
			if(FD_ISSET(SocketArray[i],&BackUpfdwrite) && SocketArray[i] == ConnectSocket)
			{
				SentBytes = send(SocketArray[i], SentBuff,sizeof(SentBuff),0);
				// Cleaning the Sent Buffer 
				memset(SentBuff,0,sizeof(SentBuff));
				
			}


		}

	} // Main menu ends here

}


The problem is that i ve noticed that still there is a delay on message transfer. It looks like there are blocking sockets.
Here is a pic.

Posted Image

#11 hplus0603   Moderators   -  Reputation: 5528

Like
0Likes
Like

Posted 24 December 2011 - 07:46 PM



        for(i=0;i<=maxDescriptor;i++)
		{
			if(FD_ISSET(i,&BackUpfdread)) 


This doesn't work well at all in Windows. sockets are handles, which can have very high values. "maxDescriptor" is ignored on input. You should test the values you know you have (the listening socket, and each client socket) rather than "all integers." You're basically testing ALMOST ALL INTEGERS to see if one of them happens to match a handle value stored in the FD_SET. That is one cause of performance problems.


I had something like that and changed it to as follows. I didn't do any measurements, but thought there was a noticeable improvement in the performance from the change. I count down rather than starting at zero and counting up. Also the code with the selrc is used to shorten this potentially long loop. selrc is the return code from select. After addressing all of the events, we can skip the rest of the loop.

for (int32_t sock = fdmax; sock > 0; --sock) {
  if (FD_ISSET(sock, &read_fds)) {
    if (mediateRequest(sock)) {
      FD_SET(cmwSendbuf.sock_, &masterwrite);
    } else {
      closeSocket(sock);
      FD_CLR(sock, &master);
    }
    if (0 == --selrc) break;
  }
}


Brian Wood
Ebenezer Enterprises
http://webEbenezer.net


That is just as bad. You want to only test the actual file descriptors that you have. Keep all user connections in an array or list or hash table, and iterate over that, testing if each users' socket is in the active set. Anything else is too sloppy for code you intend to keep.

Really, your code is similar in essence to this code:

int calculate_sum(int a, int b) {
    for (int i = MAX_INT; i > MIN_INT; --i) {
        if (i - b == a) {
            return i;
        }
    }
    return MIN_INT;
}

enum Bool { True, False, FileNotFound };

#12 wood_brian   Banned   -  Reputation: 197

Like
0Likes
Like

Posted 25 December 2011 - 11:48 PM

That is just as bad. You want to only test the actual file descriptors that you have. Keep all user connections in an array or list or hash table, and iterate over that, testing if each users' socket is in the active set. Anything else is too sloppy for code you intend to keep.


I decided to try an implementation like that and was surprised by how it turned out. It added more than 5 lines to the code and more than 2,000 bytes to the executable. At run time it also needs the memory management of the list or vector. ( I used a vector. A list would be a poor choice here I think.) The idea may still be useful, but wish it were cleaner.

Brian Wood
Ebenezer Enterprises
http://webEbenezer.net

#13 netpumber   Members   -  Reputation: 100

Like
0Likes
Like

Posted 28 December 2011 - 10:03 AM

So.. whats the problem with my new select() application ? Why the delay still exists ?
Can anyone think something ?

#14 hplus0603   Moderators   -  Reputation: 5528

Like
0Likes
Like

Posted 28 December 2011 - 12:28 PM

Did you turn on TCP_NODELAY?
Did you add a SleepEx(10, FALSE) inside your main loop on both client and server, to allow scheduling?
enum Bool { True, False, FileNotFound };

#15 netpumber   Members   -  Reputation: 100

Like
0Likes
Like

Posted 30 December 2011 - 02:39 PM

i should turn on TCP_NODELAY only to the client or in the server too ?

Edit:

I have made these changes in client

// Create a new socket to make a client connection.
[b]BOOL			bOpt = TRUE;[/b]
ConnectSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
[b]setsockopt(ConnectSocket, IPPROTO_TCP, TCP_NODELAY,(char*)&bOpt,sizeof(BOOL));[/b]


and before main loop ends in both (client & server)

}

		[b]SleepEx(10, FALSE);[/b]
	} // Main menu ends here

The results still the same.

Edited by netpumber, 31 December 2011 - 09:57 AM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS