Strange behaviour with sever - SOLVED

This topic is 4416 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hi there guys can you help me with a slight problem that i am having. Basically it adds the first client fine and lets me send messages to and from the server. But then if i add a second client it stops allowing me to send messages from the first client, but then allows them from the second. Finally if i add a third client it says that it has connected, but infact won't let me send any messages to the server. The server code is below - the only thing i can presume is that i have made a mistake with one of the break statements OR that one of the loops is incorrectly written. If anyone could point out the error of my ways it would be much appreciated. Neil P.S > This may belong in general programming but i am not sure, if so i'll post it in there once this has been closed down. Thank you

#include "winsock2.h"
#include <iostream>
#include <stdio.h>

using namespace std;

struct ClientEntry
{
int sock_number;
};

const MAX_CLIENTS = 32;
ClientEntry ClientEntryList[MAX_CLIENTS];

SendServerMessages(char *message, ClientEntry from)
{
char completeMessage[512];
int m;

for (m = 0; m<MAX_CLIENTS; m++)
{
if(ClientEntryList[m].sock_number !=-1)
{

send(ClientEntryList[m].sock_number, completeMessage, strlen(completeMessage),0);

}
}
return 0;
}

int main (int argc, char **argv)
{
int statusCode;
int Temp;
int MaxSocketNumber = -1;
int size, clientSize;
char message[256];
int l;
//	int error;

{
cerr<<"Server Startup Failed, error number "<<statusCode<<".\n";
return 255;
}
else
{
cout<<"Alls Good\n";
}

SOCKET tcpSocket;

tcpSocket = socket(AF_INET, SOCK_STREAM, 0);
if (tcpSocket==INVALID_SOCKET)
{
printf("Socket Creation Failed");
return 0;
}
else
{
cout<<"Socket Created \n";
}

serverInfo.sin_port = htons (2222);
serverInfo.sin_family = AF_INET;

if(Temp == SOCKET_ERROR)
{
Temp = WSAGetLastError();
printf("Binding Failed");
WSACleanup();
return 0;
}
else
{
cout<<"Socket Bound \n";
}

Temp = listen(tcpSocket, 32);
if(Temp==SOCKET_ERROR)
{
Temp = WSAGetLastError();
printf("Socket Listen Failed");
WSACleanup();
return 0;
}
else
{
cout <<"Socket Listening\n";
}

for (l = 0; l<MAX_CLIENTS; l++)
{
ClientEntryList[l].sock_number = -1;
}

MaxSocketNumber = tcpSocket;
while (1)
{

//		for(l=0;l<MAX_CLIENTS;l++);
//		{
//			if(ClientEntryList[l].sock_number!=-1)
//			{
//				if(ClientEntryList[l].sock_number>MaxSocketNumber)
//				{
//					MaxSocketNumber = ClientEntryList[l].sock_number;
//				}
//			}
//		}

//		if(error<0)
//		{
//			perror("Select");
//			break;
//		}//end if loop

{
/*SOCKET*/int clientAccept;

printf ("Waiting for Client to Connect...\n");
clientAccept = accept(tcpSocket,(struct sockaddr*) &client, &clientSize);
printf("New Client Connected from IP Address %s and on port %ld\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));

for (l=0;l<MAX_CLIENTS;l++)
{
if(ClientEntryList[l].sock_number == -1)
{
ClientEntryList[l].sock_number = clientAccept;
memcpy(&ClientEntryList[l].client,&client,sizeof(client));
if (ClientEntryList[l].sock_number > MaxSocketNumber)
{
MaxSocketNumber = ClientEntryList[l].sock_number;
}
break;
}//end if loop

if(l==MAX_CLIENTS)
{
strcpy(message,"Server Busy Please Try Again Later\n");
send(tcpSocket,message,strlen(message),0);
closesocket (clientAccept);
break;
}//end if loop
}//end for loop
}

for (l=0;l<MAX_CLIENTS;l++)
{
if(ClientEntryList[l].sock_number !=-1)
{
{
size = recv(ClientEntryList[l].sock_number,message,512,0);
if(size>0)
{
message[size] = 0;
SendServerMessages(message,ClientEntryList[l]);
break;
}//end if loop
else
{
ClientEntryList[l].sock_number = -1;
SendServerMessages("Client Has Left \n", ClientEntryList[l]);
break;
}//end else loop
}//end FD_ISSET loop
}//end client entry loop
}//end for loop

}//end while(1) loop

closesocket (tcpSocket);
for (l=0;l<MAX_CLIENTS;l++)
{
if(ClientEntryList[l].sock_number!=-1)
{
closesocket(ClientEntryList[l].sock_number);
}//close if loop
}//close for loop
return 0;
}//end main


Cheers again for any help that can be given. Neil [Edited by - neilski_2003 on January 23, 2006 2:50:48 PM]

Share on other sites
You're using blocking sockets, i suggest looking up asyncronous sockets or maybe threads. Threads would be the wrong way to go in this case since asyncronous sockets allow multiple clients to connect and recieve messages, threads are good to learn though. Here's a link with a nice example of what you should do, just scroll down a bit past the first examples. http://www.beej.us/guide/bgnet/output/html/advanced.html

Share on other sites
Can you please be a bit more specific as to what the difference is.

From what i can see the only difference is the use of the select() function when cycling through connections, and i thought i had done this in my code - there is a definate call to select (maybe its in the wrong place?)

I use the FD_SET and FD_ZERO to put the new sockets in sets (as far as i am aware) and the run select on the socket sets to check for new messages. Does that not mean i am running non-blocking sockets.

Apologies if the questions are ridiculously stupid but i am literally learning this from scratch with no experience whatsoever so all help would be well appreciated.

Also - i have tried the asynchronous route but don't know how to create windows so that really is a no no for me - just plain threading using select() is the route i would like to take at the moment as its the one i have the most information about even if i can't get it right!!!

Cheers
Neil

Share on other sites
Blocking sockets won't return from a read or write operation until it's completed. Non-blocking sockets will return immediately. In the case of read this is when the specified amount of data has been retrieved, in the case of write when that amount of data has been sent.

Sockets have a certain buffer of data they can contain. If you try to send too much your transmission is truncated, and you need to append to the stream when the buffer is available again. Remember to check your return values!
Interpreting these may vary between linux and windows. Check defined constants!

Share on other sites
how do i check if my sockets are blocking or non blocking then?

I'm not sure how to differentiate between the two different types to be honest.

I would obviously like to be using non blocking sockets thatreturn straight away, and just keep looping through the lists asking for activity.(i take it the way to do this is by looping through select() calls?)

Cheers again.

Share on other sites
Select will return the socket ID in the list if there is data pending on a non-blocking socket (that buffer isn't empty).

The method of setting the socket operation is ioctl( ... ) for berkeley and ioctlsocket( ... ) for winsock. Both create blocking sockets by default.

I suggest making a socket class to wrap all the functionality up.

Share on other sites
Note that recv() is different from read(). If select() says that a socket is ready for reading then the next call to recv() is guaranteed not to block. recv() will return whatever is available in the buffer; it will not wait for more data. recv() on a blocking socket only blocks if the buffer is empty at the time of call.

Share on other sites
OK

I will add the code again below with notes as to where i think the non blocking code should go - could someone help me out with that as i can only seem to find unix examples on the net and i'm not the greatest and converting them to what i need - its something to do with flags and O|NONBLOCK but thats about ym understanding of it.

Anyway the current beahviour of the server is to allow for a new connection and send messages to and from it. Then if i add a new client the first one almost drops out and only the second client can send and recieve messages, then the same for a third client etc etc, so only the last added client can send messages.

btw i am using multiple telnet clients connecting to the computers loop back address so would this in any way explain the behaviour?

This leaves me to believe i have either got one of the loops wrong or the select call? If anyone could take a look that would be great.

Cheers guys

[source lang = "cpp"]#include "winsock2.h"#include &lt;iostream&gt;#include &lt;stdio.h&gt;using namespace std;struct ClientEntry{	int sock_number;	SOCKADDR_IN client;};const MAX_CLIENTS = 32;ClientEntry ClientEntryList[MAX_CLIENTS];SendServerMessages(char *message, ClientEntry from){	char completeMessage[512];	int m;	sprintf(completeMessage, "[%s:%ld]:%s", inet_ntoa(from.client.sin_addr),ntohs(from.client.sin_port),message);	for (m = 0; m&lt;MAX_CLIENTS; m++)	{		if(ClientEntryList[m].sock_number !=-1)		{					send(ClientEntryList[m].sock_number, completeMessage, strlen(completeMessage),0);					}	}	return 0;}//int sock;//void settononblocking(sock)//{//	int opts;////	opts = fcntl(sock,F_GETFL));//	if(opts&lt;0)//	{//		perror("fcntl(F_GETFL)");//		exit(EXIT_FAILURE);//	}////	opts = (opts|O_NONBLOCK);//	if (fcntl(sock,F_SETFL,opts)&lt;0)//	{//		perror("fcntl(F_SETFL)");//		exit(EXIT_FAILURES);//	}//	return;//}int main (int argc, char **argv){	WSAData wsaData;	int statusCode;	int Temp;	FD_SET read;	int MaxSocketNumber = -1;	SOCKADDR_IN client;	int size, clientSize;	char message[256];	int l;	struct timeval Timeout;//	int error;	if ((statusCode = WSAStartup(MAKEWORD(1,1),&wsaData))!=0)	{		cerr&lt;&lt;"Server Startup Failed, error number "&lt;&lt;statusCode&lt;&lt;".\n";		return 255;	}	else	{		cout&lt;&lt;"Alls Good\n";	}	SOCKET tcpSocket;	tcpSocket = socket(AF_INET, SOCK_STREAM, 0);	if (tcpSocket==INVALID_SOCKET)	{		printf("Socket Creation Failed");		return 0;	}	else	{		cout&lt;&lt;"Socket Created \n";	}	//set to non blocking socket.	SOCKADDR_IN serverInfo;	serverInfo.sin_port = htons (2222);	serverInfo.sin_family = AF_INET;	serverInfo.sin_addr.s_addr = inet_addr("127.0.0.1");	Temp = (bind(tcpSocket,(LPSOCKADDR)&serverInfo, sizeof(serverInfo)));	if(Temp == SOCKET_ERROR)	{		Temp = WSAGetLastError();		printf("Binding Failed");		WSACleanup();		return 0;	}	else	{		cout&lt;&lt;"Socket Bound \n";	}	Temp = listen(tcpSocket, 32);	if(Temp==SOCKET_ERROR)	{		Temp = WSAGetLastError();		printf("Socket Listen Failed");		WSACleanup();		return 0;	}	else	{		cout &lt;&lt;"Socket Listening\n";	}	for (l = 0; l&lt;MAX_CLIENTS; l++)	{		ClientEntryList[l].sock_number = -1;	}	FD_ZERO(&read);	FD_SET(tcpSocket, &read);	MaxSocketNumber = tcpSocket;	while (1)	{//		FD_ZERO(&read);		FD_SET(tcpSocket, &read);	//	Timeout.tv_sec = 0;	//	Timeout.tv_usec= 0;		/*error =*/ select(MaxSocketNumber+1,&read,0,0,/*&Timeout*/0);//		if(error&lt;0)//		{//			perror("Select");//			break;//		}//end if loop		if(FD_ISSET(tcpSocket,&read))		{			clientSize = sizeof(SOCKADDR_IN);			/*SOCKET*/int clientAccept;			printf ("Waiting for Client to Connect...\n");			clientAccept = accept(tcpSocket,(struct sockaddr*) &client, &clientSize);//			settononblocking(clientAccept);			printf("New Client Connected from IP Address %s and on port %ld\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));			for (l=0;l&lt;MAX_CLIENTS;l++)			{				if(ClientEntryList[l].sock_number == -1)				{					ClientEntryList[l].sock_number = clientAccept;					memcpy(&ClientEntryList[l].client,&client,sizeof(client));					FD_SET(ClientEntryList[l].sock_number, &read);					if (ClientEntryList[l].sock_number &gt; MaxSocketNumber)					{						MaxSocketNumber = ClientEntryList[l].sock_number;					}					break;				}//end if loop							if(l==MAX_CLIENTS)				{					strcpy(message,"Server Busy Please Try Again Later\n");					send(tcpSocket,message,strlen(message),0);					closesocket (clientAccept);					break;				}//end if loop			}//end for loop		}		for (l=0;l&lt;MAX_CLIENTS;l++)		{			if(ClientEntryList[l].sock_number !=-1)			{				if(FD_ISSET(ClientEntryList[l].sock_number,&read))				{					size = recv(ClientEntryList[l].sock_number,message,512,0);					if(size&gt;0)					{						message[size] = 0;						printf("[%s] sends %s\n",inet_ntoa(ClientEntryList[l].client.sin_addr), message);						SendServerMessages(message,ClientEntryList[l]);						break;					}//end if loop					else					{						FD_CLR(ClientEntryList[l].sock_number, &read);						ClientEntryList[l].sock_number = -1;						printf("Client %s has left\n", inet_ntoa(ClientEntryList[l].client.sin_addr));						SendServerMessages("Client Has Left \n", ClientEntryList[l]);						break;					}//end else loop				}//end FD_ISSET loop			}//end client entry loop		}//end for loop	}//end while(1) loop	closesocket (tcpSocket);	for (l=0;l&lt;MAX_CLIENTS;l++)	{		if(ClientEntryList[l].sock_number!=-1)		{			closesocket(ClientEntryList[l].sock_number);		}//close if loop	}//close for loop	return 0;}//end main

Share on other sites
Where you're using fcntl you need to use the ioctl functions I mentioned above.

Here's a code snippet from my socket class:

bool WSSocket::setBlocking(bool bBlocking){	if (!m_bReady) 	{		m_pLog->log("WSSocket %x trying to set blocking mode before ready!\n",this);		return false;	// Socket must be created to change mode	}	unsigned long val;#ifdef WSCORE_LINUX	if (bBlocking)	{		// We want to be blocking		val = 0;		if (!m_bBlocking)	// We WANT to be blocking but we're NOT		{			if (ioctl(m_sock, FIONBIO, &val)<0)				return false;			m_bBlocking = true;			return true;		}		return true; // We blocking and we want to be	}	else	{		// We don't want to be blocking		val = 1;		if (m_bBlocking)	// We DON'T want to be blocking but we ARE		{			if (ioctl(m_sock, FIONBIO, &val)<0)				return false;			m_bBlocking = false;			return true;		}		return true; // We not blocking and we don't want to be	}#endif#ifdef WSCORE_WIN32	// ioctl only applies to sockets under linux - hence ioctlsocket.	if (bBlocking)	{		// We want to be blocking		val = 0;		if (!m_bBlocking)	// We WANT to be blocking but we're NOT		{			if (ioctlsocket(m_sock,FIONBIO,&val)<0)				return false;			m_bBlocking = true;			return true;		}		return true; // We blocking and we want to be	}	else	{		// We don't want to be blocking		val = 1;		if (m_bBlocking)	// We DON'T want to be blocking but we ARE		{			if (ioctlsocket(m_sock,FIONBIO,&val)<0)				return false;			m_bBlocking = false;			return true;		}		return true; // We are not blocking and we don't want to be	}#endif};

Edit: 1 and 0 errors fixed.

[Edited by - _winterdyne_ on January 22, 2006 11:08:05 AM]

Share on other sites
Somewhat rubbishly i have left the code on my computer indoors and am now at the library without it but i will soldier on with as many questions as i can remeber anyway.

I basically tried this in my code but got an error back saying something about a function style header. I just planned on calling this after every accept call to make the accepted socket non blocking, and obviously the same with the listening socket.

here it is
[source lang = "cpp"]void setnonblocking(sock)int sock;{	int opts;	opts = fcntl(sock,F_GETFL); //is it here that i should be using ioctrl instead of fcntl?	if (opts < 0) {		perror("fcntl(F_GETFL)");		exit(EXIT_FAILURE);	}	opts = (opts | O_NONBLOCK);	if (fcntl(sock,F_SETFL,opts) < 0) {		perror("fcntl(F_SETFL)");		exit(EXIT_FAILURE);	}	return;}[\source]anyway errors come back on fcntl, F_GETFL and O_NONBLOCK.  I am presuming that i am missing out a header or something. As i say i am new to this and am picking it up from scraps off the internet and without a good book so apologies if i seem to be asking the same questions over and over i just don't really understand whats going wrong half the time.

Share on other sites
Hello,

I noticed that your code snippet uses the flag value "1" to set the socket to blocking. Isn't this backwards? The SDK says to use non-zero value for non-blocking. I want to make sure I did not misread the SDK, because I am using non-blocking sockets in my game :) It seems to work fine, but you never know.

EDIT : To clarify, my question is for _winterdyne_

Thanks.
-Mike

[Edited by - MikeVitt on January 21, 2006 3:18:09 PM]

Share on other sites
1 is a non-zero value. :-)
It works as per the example - I did have a bug when I posted it - the logging call was after a return, and so was never called. Fixed it when I noticed it.

Share on other sites
Right, but isn't your code setting the blocking socket to 1? Maybe I'm not reading it correctly, but that's what it looks like. Either way, you answered my question. I wanted to make sure "1" is for non-blocking :)

Thanks.
-Mike

Share on other sites
Hmm... you're right, Mike. 1 and 0 in wrong places. I'm SURE I checked that on MSDN and several linux sites. I'm starting to think I might be mildly yes/no dyslexic or something. I get a lot of bugs like that. Very few typo's, but lots of those. I'll edit the post to be correct.

++ for you!

Share on other sites
Thanks :) I just happened to notice it and wanted to make sure I was seeing it correctly.

Take care.
-Mike