Advertisement

Problem with non-blocking... But blocking works fine?

Started by November 20, 2003 07:41 AM
6 comments, last by Trond A 21 years, 2 months ago
http://www.rafb.net/paste/results/J3158772.html The above link is to my server code where my error must be, since I can send messages from it using a blocking, but when I check connections non-blocking and try to send after that, I can''t send out! I''m trying to figure out what I''m doing wrong, but I haven''t yet... Any ideas? Thanks, Trond
-Trond
For the life of me I cannot figure what your actual question is.



Can you restate?
Advertisement
Just one question does your code break out of that infinite loop? If it does can you post your "send" function?
What error do you get? WSAEWOULDBLOCK (10035)? I bet it is.

Use WSAGetLastError after the call that causes a problem and tell me what it is.



"Absorb what is useful, reject what is useless, and add what is specifically your own." - Lee Jun Fan
"Absorb what is useful, reject what is useless, and add what is specifically your own." - Lee Jun Fan
I'll try to explain better, here's what happens:
example1:works:
-init wsock
-accept client (blocks until client connects)
-send msg to client

example2:does not work:
-init wsock the same way as above
-go in an infinite loop and wait for clients by using select() and accepting if any clients try to connect. this does not block as in the above "example", although it may seem that way because of the infinite loop.
-try to send msg to client (which HAS connected), but get a failure...

I get out of the infinite loop by pressing escape... I made it for testing when I figured I couldn't send after accepting clients non-blocking.

The error code I get from WSAGetLastError() is 0...

I do the send at the bottom of the constructor BTW, after I have accepted a client.

Thanks again,
Trond

[edited by - Trond A on November 20, 2003 12:37:15 PM]
-Trond
paste the code again... it seems to be gone
Advertisement
I have to agree that you''re not being very clear, perhaps some code would help?

Incidentally, if you get 0 from WSAGetLastError then there is no error, which means that nothing is wrong (assuming that you are calling WSAGetLastError in the correct place which is why you need to post some code if possible)




"Absorb what is useful, reject what is useless, and add what is specifically your own." - Lee Jun Fan
"Absorb what is useful, reject what is useless, and add what is specifically your own." - Lee Jun Fan
The place I pasted to seemed to be down...

Anyway, I made it work with non-blocking both for a server and for a client. However, I have encountered a new problem: (I''ll TRY to explain it a bit better than my previous)

I start a server which loops infinitly doing a select() each loop. (Timeout = 0) I get the client to connect without problems, and when I have connected, I send a message from the client to the server. The server hooks it from the select() function, reads it and tries to send it back. It seems like it is sent from the server, but the client never receives it. I use the select() function on the client as well, using timeout = 0. I have tried putting the timeout to various values, and I got it to work if I put it on 0.5sec (probably others too, but not much less).

My real question here is: Is it not possible to receive data via the select() function unless there is a relatively high timeout? I need the select() function to block as few ms as possible, since I''m trying to put up something I can use in a simple real-time game...

Here is the server relevant code I use (don''t know who made the original code, but I didn''t, only modified it) :
#include "ws-util.h"#include <winsock.h>#include <iostream>using namespace std;////////////////////////////////////////////////////////////////////////// Constants const int kBufferSize = 1024;        ////////////////////////////////////////////////////////////////////////// Globals and types/*struct Connection {    SOCKET sd;    char acBuffer[kBufferSize];    int nCharsInBuffer;    Connection(SOCKET sd_) : sd(sd_), nCharsInBuffer(0) { }};typedef vector<Connection> ConnectionList;ConnectionList gConnections;*/typedef struct{	SOCKET	sd;	char	acBuffer[kBufferSize];	int		nCharsInBuffer;	bool	used;}StrClient;StrClient taConnection;////////////////////////////////////////////////////////////////////////// PrototypesSOCKET SetUpListener(const char* pcAddress, int nPort);void AcceptConnections(SOCKET ListeningSocket);//// DoWinsock /////////////////////////////////////////////////////////// The module''s driver function -- we just call other functions and// interpret their results.int DoWinsock(const char* pcAddress, int nPort){    cout << "Establishing the listener..." << endl;    SOCKET ListeningSocket = SetUpListener(pcAddress, htons(nPort));    if (ListeningSocket == INVALID_SOCKET) 	{        cout << endl << WSAGetLastErrorMessage("establish listener") << endl;        return 3;    }    cout << "Waiting for connections...\n" << flush;    while (1) 	{		Sleep(300);//delay just to see debug messages        AcceptConnections(ListeningSocket);  //      cout << "Acceptor restarting..." << endl;    }	closesocket(taConnection.sd);    return 0;   // warning eater}//// SetUpListener /////////////////////////////////////////////////////// Sets up a listener on the given interface and port, returning the// listening socket if successful; if not, returns INVALID_SOCKET.SOCKET SetUpListener(const char* pcAddress, int nPort){    u_long nInterfaceAddr = inet_addr(pcAddress);    if (nInterfaceAddr != INADDR_NONE) 	{        SOCKET sd = socket(AF_INET, SOCK_STREAM, 0);        if (sd != INVALID_SOCKET) 		{            sockaddr_in sinInterface;            sinInterface.sin_family			= AF_INET;            sinInterface.sin_addr.s_addr	= nInterfaceAddr;            sinInterface.sin_port			= nPort;            if (bind(sd, (sockaddr*)&sinInterface, sizeof(sockaddr_in)) != SOCKET_ERROR) 			{                listen(sd, SOMAXCONN);                return sd;            }            else {                cerr << WSAGetLastErrorMessage("bind() failed") <<                        endl;            }        }    }    return INVALID_SOCKET;}//// SetupFDSets ///////////////////////////////////////////////////////// Set up the three FD sets used with select() with the sockets in the// connection list.  Also add one for the listener socket, if we have// one.void SetupFDSets(fd_set& ReadFDs, fd_set& WriteFDs, fd_set& ExceptFDs, SOCKET ListeningSocket = INVALID_SOCKET) {    FD_ZERO(&ReadFDs);    FD_ZERO(&WriteFDs);    FD_ZERO(&ExceptFDs);    // Add the listener socket to the read and except FD sets, if there    // is one.    if (ListeningSocket != INVALID_SOCKET) 	{        FD_SET(ListeningSocket, &ReadFDs);        FD_SET(ListeningSocket, &ExceptFDs);    }	if (taConnection.used)	{		if (taConnection.nCharsInBuffer < kBufferSize)		{			FD_SET(taConnection.sd, &ReadFDs);		}		if (taConnection.nCharsInBuffer > 0)		{			FD_SET(taConnection.sd, &WriteFDs);		}		FD_SET(taConnection.sd, &ExceptFDs);	}}//// ReadData //////////////////////////////////////////////////////////// Data came in on a client socket, so read it into the buffer.  Returns// false on failure, or when the client closes its half of the// connection.  (WSAEWOULDBLOCK doesn''t count as a failure.)bool taReadData(StrClient *taconn){	int bytes_recv = recv(taconn->sd, taconn->acBuffer + taconn->nCharsInBuffer, kBufferSize - taconn->nCharsInBuffer, 0);	if (bytes_recv == 0)	{		taconn->used = false;		closesocket(taconn->sd);		cout << "Socket closed by client\n";		return false;	}	if (bytes_recv == SOCKET_ERROR)	{		cout << "Socket error\n";		return false;	}	taconn->nCharsInBuffer += bytes_recv;	cout << taconn->acBuffer << " came from client\n";	return true;}//// WriteData /////////////////////////////////////////////////////////// The connection is writable, so send any pending data.  Returns// false on failure.  (WSAEWOULDBLOCK doesn''t count as a failure.)bool taWriteData(StrClient *taconn){	cout << "Preparing to send: " << taconn->acBuffer << "\n";	int bytes_sent = send(taconn->sd, taconn->acBuffer, taconn->nCharsInBuffer, 0);	if (bytes_sent == SOCKET_ERROR)	{		cout << "Socket error in WriteData\n";		return false;	}	if (bytes_sent == taconn->nCharsInBuffer)	{		cout << "Done returning packet from client\n";		taconn->nCharsInBuffer = 0;	}	else	{		taconn->nCharsInBuffer -= bytes_sent;		memmove(taconn->acBuffer, taconn->acBuffer + bytes_sent, taconn->nCharsInBuffer);	}	return true;}//// AcceptConnections /////////////////////////////////////////////////// Spin forever handling connections.  If something bad happens, we// return.void AcceptConnections(SOCKET ListeningSocket){    sockaddr_in sinRemote;    int nAddrSize = sizeof(sinRemote);	taConnection.nCharsInBuffer = 0;    while (1) 	{        fd_set ReadFDs, WriteFDs, ExceptFDs;        SetupFDSets(ReadFDs, WriteFDs, ExceptFDs, ListeningSocket);		printf("Waiting for data on socket\n");		timeval timeout;		timeout.tv_sec = 0;		timeout.tv_usec = 0;        if (select(0, &ReadFDs, &WriteFDs, &ExceptFDs, &timeout) > 0) 		{            //// Something happened on one of the sockets.            // Was it the listener socket?...            if (FD_ISSET(ListeningSocket, &ReadFDs)) 			{				MessageBox(0, "Accepting client", "INFO", MB_OK);                SOCKET sd = accept(ListeningSocket, (sockaddr*)&sinRemote, &nAddrSize);                				if (sd != INVALID_SOCKET) 				{                    // Tell user we accepted the socket, and add it to                    // our connecition list.                    cout << "Accepted connection from " << inet_ntoa(sinRemote.sin_addr) << ":" << ntohs(sinRemote.sin_port) << ", socket " << sd << "." << endl;                    					taConnection.sd		= sd;					taConnection.used	= true;					memset(taConnection.acBuffer, 0, sizeof(taConnection.acBuffer));                    // Mark the socket as non-blocking, for safety.                    u_long nNoBlock = 1;                    ioctlsocket(sd, FIONBIO, &nNoBlock);                }                else 				{                    cerr << WSAGetLastErrorMessage("accept() failed") << endl;				//	Sleep(200);                    return;                }            }            else if (FD_ISSET(ListeningSocket, &ExceptFDs)) 			{                int err;                int errlen = sizeof(err);                getsockopt(ListeningSocket, SOL_SOCKET, SO_ERROR, (char*)&err, &errlen);                cerr << WSAGetLastErrorMessage("Exception on listening socket: ", err) << endl;                return;            }			//if we got nothing in on the server socket, check the client socket			if (taConnection.used)			{				if (FD_ISSET(taConnection.sd, &ExceptFDs))				{					cout << "Socket error, got exception\n";					closesocket(taConnection.sd);					return;				}				else				{					if (FD_ISSET(taConnection.sd, &ReadFDs))					{						cout << "Client tries to send something\n";						Sleep(500);						bool success = taReadData(&taConnection);						if (success == false)						{							cout << "Assuming client disconnected\n";							closesocket(taConnection.sd);							taConnection.used = false;						}						FD_CLR(taConnection.sd, &ReadFDs);					}					if (FD_ISSET(taConnection.sd, &WriteFDs))					{						cout << "Returning packet to client\n";						Sleep(500);						bool success = taWriteData(&taConnection);						if (success == false)						{							cout << "Error when returning packet\n";						}						FD_CLR(taConnection.sd, &WriteFDs);					}				}			}        }        else 		{		//	Sleep(200);        //    cerr << WSAGetLastErrorMessage("select() failed") << endl;            return;        }    }}


And here is the client relevant code (the ClsClient class constructor):
#include "winsock2.h"#include "stdio.h"class ClsWSClient{private:	int			returnmsg;	WSADATA		wsadata;	SOCKET		sock_client;	sockaddr_in addr_server;	timeval		timeout;public:	ClsWSClient()	{		timeout.tv_sec	= 0;		timeout.tv_usec = 0;		printf("Creating ClsWSClient\n");		returnmsg = WSAStartup(0x202, &wsadata);		if (returnmsg)		{			printf("Failed to startup WinSock\n");		}		addr_server.sin_family		= AF_INET;		addr_server.sin_addr.s_addr = inet_addr("128.39.146.163");		addr_server.sin_port		= htons((u_short)4242);		sock_client = socket(AF_INET, SOCK_STREAM, 0);//IPPROTO_TCP);		if (sock_client == INVALID_SOCKET)		{			printf("Failed to create socket\n");			WSACleanup();			return;		}		if (connect(sock_client, (sockaddr*)&addr_server, sizeof(addr_server)) != 0)		{			printf("Failed to connect\n");			WSACleanup();			return;		}		else		{			printf("Connected to server\n");		}		fd_set fds_read;		fd_set fds_write;		fd_set fds_except;		FD_ZERO(&fds_read);		FD_ZERO(&fds_write);		FD_ZERO(&fds_except);		sendData();		printf("Sent data to server\n");		FD_SET(sock_client, &fds_read);		u_long nNoBlock = 1;        ioctlsocket(sock_client, FIONBIO, &nNoBlock);		while(1)		{			if (GetAsyncKeyState(VK_RETURN))			{				printf("Stopped waiting for incoming data\n");				break;			}			printf("Waiting for data\n");			Sleep(100);			int s = select(0, &fds_read, &fds_write, &fds_except, &timeout);						if (s > 0)			{				printf("Received som kind of data\n");				if (FD_ISSET(sock_client, &fds_read))				{					receiveData();					break;				}			}		}	/*	char text[128];								if (recv(sock_client, text, sizeof(text), 0) == SOCKET_ERROR)		{			printf("Failed to receive expected message\n");		}		else		{			printf("Server: %s\n", text);		}*/		system("pause");	}	void sendData()	{		int bytessent;		unsigned long messagesize;		char text[1024];		sprintf(text, "I have connected");		messagesize = strlen(text);//		messagesize = htonl(messagesize);//		bytessent = send(sock_client, (char*)&messagesize, sizeof(messagesize), 0);/*		if (bytessent == SOCKET_ERROR)		{			printf("Failed to send data size\n");			return;		}		messagesize = ntohl(messagesize);*/		bytessent = send(sock_client, text, messagesize, 0);		if (bytessent == SOCKET_ERROR)		{			printf("Failed to send data\n");			return;		}	}	void receiveData()	{		int bytesreceived;		unsigned long messagesize;		char datareceived[4096];/*		bytesreceived = recv(sock_client, (char*)&messagesize, sizeof(messagesize), 0);		if (bytesreceived == SOCKET_ERROR)		{			printf("Receive failed\n");			return;		}		messagesize = ntohl(messagesize);*/		bytesreceived = recv(sock_client, datareceived, sizeof(datareceived), 0);		if (bytesreceived == SOCKET_ERROR)		{			printf("Receive failed\n");			return;		}		messagesize = strlen(datareceived);		//null terminate string we got		datareceived[messagesize] = ''\0'';		printf("Server: %s\n", datareceived);	}	~ClsWSClient()	{		closesocket(sock_client);		printf("Destroying ClsWSClient\n");		WSACleanup();	}};#define MAX_CLIENTS 5typedef struct{	SOCKET		socket;	sockaddr_in	address;}StClient;class ClsWSServer{private:	int			returnmsg;	WSADATA		wsadata;	SOCKET		sock_server;	sockaddr_in addr_local;	int			connected;	StClient	client[MAX_CLIENTS];public:	ClsWSServer()	{		connected = 0;		printf("Creating ClsWSServer\n");		returnmsg = WSAStartup(0x202, &wsadata);		if (returnmsg)		{			printf("Failed to startup WinSock\n");		}		addr_local.sin_family = AF_INET;		addr_local.sin_addr.s_addr = INADDR_ANY;		addr_local.sin_port = htons((u_short)20248);		sock_server = socket(AF_INET, SOCK_STREAM, 0);//IPPROTO_TCP);		if (sock_server == INVALID_SOCKET)		{			printf("Failed to create socket\n");			WSACleanup();			return;		}		if (bind(sock_server, (sockaddr*)&addr_local, sizeof(addr_local)) != 0)		{			printf("Failed to bind socket\n");			WSACleanup();			return;		}		if (listen(sock_server, MAX_CLIENTS) == SOCKET_ERROR)//max 5 clients		{			printf("Can''t listen\n");			WSACleanup();			return;		}		printf("Waiting for clients...\n");		while(connected < MAX_CLIENTS)		{			int	sockaddr_size = sizeof(sockaddr_in);			if ((client[connected].socket = accept(sock_server, (sockaddr*)&client[connected].address, &sockaddr_size)) == SOCKET_ERROR)			{				printf("Client failed to connect\n");				return;			}			else			{				printf("Client %i connected from %s\n", connected, inet_ntoa(client[connected].address.sin_addr));				connected++;			}			if (MessageBox(0, "Wait for more clients?", "Connections", MB_YESNO) == IDNO)			{				break;			}		}		char text[128];		sprintf(text, "Welcome!\n");								if (send(client[0].socket, text, sizeof(text), 0) == SOCKET_ERROR)		{			printf("Failed to send message to client %i at %s\n", 0, inet_ntoa(client[0].address.sin_addr));		}		else		{			printf("Sent message to client %i\n", 0);		}			for (int cl = 0; cl < connected; cl++)		{			receiveData(cl);			sendData(cl);		}	}	~ClsWSServer()	{		for (int i = 0; i < MAX_CLIENTS; i++)		{			closesocket(client[i].socket);		}		closesocket(sock_server);		printf("Destroying ClsWSServer\n");		WSACleanup();	}	void sendData(int index)	{		int bytessent;		unsigned long messagesize;		char *ip = inet_ntoa(client[index].address.sin_addr);		char text[4096];		sprintf(text, "Welcome to this server, you have index %i and IP %s", index, ip);		messagesize = strlen(text);		messagesize = htonl(messagesize);		bytessent = send(client[index].socket, (char*)&messagesize, sizeof(messagesize), 0);		if (bytessent == SOCKET_ERROR)		{			printf("Failed to send data size\n");			return;		}		messagesize = ntohl(messagesize);		bytessent = send(client[index].socket, text, messagesize, 0);		if (bytessent == SOCKET_ERROR)		{			printf("Failed to send data\n");			return;		}	}	void receiveData(int index)	{		int bytesreceived;		unsigned long messagesize;		char datareceived[4096];		bytesreceived = recv(client[index].socket, (char*)&messagesize, sizeof(messagesize), 0);		if (bytesreceived == SOCKET_ERROR)		{			printf("Receive failed\n");			return;		}		messagesize = ntohl(messagesize);		bytesreceived = recv(client[index].socket, datareceived, messagesize, 0);		if (bytesreceived == SOCKET_ERROR)		{			printf("Receive failed\n");			return;		}		//null terminate string we got		datareceived[messagesize] = ''\0'';		printf("Client %i: %s\n", index, datareceived);	}};int main(){	if (MessageBox(0, "Is this a client?", "Client/Server", MB_YESNO) == IDYES)	{		ClsWSClient *wsclient = new ClsWSClient();		delete wsclient;	}	else	{		ClsWSServer *wsserver = new ClsWSServer();		delete wsserver;	}	return 1;}

Note that I do not use anything from the ClsServer class.

Thank you for your time!
-Trond
-Trond

This topic is closed to new replies.

Advertisement