Advertisement

Problems with Asynchronous Socket

Started by June 22, 2006 10:16 AM
10 comments, last by Haytil 18 years, 7 months ago
I'm having difficulties in using asynchronous sockets. I'm using Windows XP and programming in C++. My goal is to have two programs, a server program and a client program, talk to each other using asynchronous sockets, over a LAN. I've gotten the program to work using blocking sockets, so I know the network is not an issue, but rather, the program. Also, when using the blocking-socket version of the server program and the asynchronous-socket version of the client program, everything seems to work. However, it doesn't work when I try to use the asynchronous-socket version of the server program, so that must be the problem. When debugging, after attempting to connect with the client program, I find that my server program never fires a WM_SOCKET (my custom message given to WSAASyncSelect() function) with the FD_ACCEPT parameter. So somehow the message is never received that the client wants to connect. Neither the bind() nor listen() functions ever return an error, so everythign looks like it should be fine. My source code is fairly messy (and embedded in a lot of stuff specific to my program, and not the problem), so if anyone has or knows of code for a Win32 Asynchronous client/server program(s), I'd appreciate being able to compare it to my code to see where the problem is. I've checked out the articles on gamedev and on google, but I can't seem to find the code for both server and clients with asynchronous sockets that I can test out and then compare. If not, I'll try and clean up the code so I can post it for help. Thanks. -Gauvir_Mucca
post WSAAsyncSelect() and definition message handler WM_SOCKET

Kuphryn
Advertisement
Here is the relevant header information:

#define WM_SOCKET		(WM_USER + 1)class IConnection{	public:		IConnection();		~IConnection();		bool Check_Receive_Buffer(void);		void Flush_Receive_Buffer(void);		void Send_Data(char* i_buffer, int i_buffer_length);		bool Receive_Data(void);		bool Check_For_Active_Connection();		void Close_Connection();		char m_Receive_Buffer[RECEIVE_BUFFER_SIZE];	protected:		bool Load_Winsock_Library(void);		int m_Port;		bool m_Receive_Buffer_Full;		bool m_Active_Connection;		SOCKET m_Socket;		WSADATA m_Winsock_Data;};class CServerConnection : public IConnection{	public:		CServerConnection();		~CServerConnection();		bool Begin_Listening_For_Connections(int i_port = DEFAULT_PORT);		bool Check_Listening_For_Connections(void);		void Stop_Listening_For_Connections(void);		bool Accept_Connection(void);	protected:		bool m_Listening_For_Connections;		SOCKET m_Listening_Socket;		sockaddr_in m_Server_Address;		sockaddr m_Client_Address;				int m_addr_size;};


Here is the function that starts listening for connections:

bool CServerConnection::Begin_Listening_For_Connections(int i_port){	m_Server_Address.sin_family = AF_INET;	m_Server_Address.sin_port = htons(m_Port);	m_Server_Address.sin_addr.s_addr = htonl(INADDR_ANY);	m_Listening_Socket = socket(AF_INET, SOCK_STREAM, 0);	if(WSAAsyncSelect(m_Listening_Socket, main_window_handle, WM_SOCKET, 					(FD_READ | FD_WRITE | FD_ACCEPT | FD_CLOSE)) == SOCKET_ERROR)	{		throw Exception("Unable to set up asynchronous server socket", __FILE__, __LINE__);		return(false);	}	if (bind(m_Listening_Socket, (LPSOCKADDR)&m_Server_Address, 				sizeof(m_Server_Address)) == SOCKET_ERROR)	{	//	throw Exception("Server unable to bind socket for listening.", __FILE__, __LINE__);			WSACleanup();		m_Listening_For_Connections = false;			return(false);	}	if (listen(m_Listening_Socket, 1) == SOCKET_ERROR)	{	//	throw Exception("Server unable to begin listening.", __FILE__, __LINE__);		WSACleanup();		m_Listening_For_Connections = false;				return(false);	}	m_Listening_For_Connections = true;		return(true);}


Here is the message handler code:

CServerConnection* Server_Connection = NULL;LRESULT CALLBACK WindowProc(HWND hwnd, 						    UINT msg,                             WPARAM wparam,                             LPARAM lparam){	// this is the main message handler of the system	PAINTSTRUCT	ps;		   // used in WM_PAINT	HDC			hdc;	   // handle to a device context	// what is the message 	switch(msg)	{				case WM_CREATE: 			{				// do initialization stuff here				return(0);			} break;		case WM_PAINT:			{				 // start painting				 hdc = BeginPaint(hwnd,&ps);				     // end painting			     EndPaint(hwnd,&ps);			     return(0);			} break;		case WM_DESTROY: 			{				// kill the application							PostQuitMessage(0);				return(0);			} break;		case WM_SOCKET:			{				switch(WSAGETSELECTEVENT(lparam))				{					case FD_READ:						{						} break;						case FD_WRITE:						{						} break;						case FD_ACCEPT:						{							if (Server_Connection->Check_Listening_For_Connections())							{								if (!Server_Connection->Check_For_Active_Connection())								{									Server_Connection->Accept_Connection();									Server_Connection->Stop_Listening_For_Connections();									Server_Connection->Flush_Receive_Buffer();																				}							}						} break;						case FD_CONNECT:						{						} break;						case FD_CLOSE:						{						         Server_Connection->Close_Connection();							} break;				}			} break;		case WM_ACTIVATE:			{} break;	default:break;    } // end switch	// process any messages that we didn't take care of 	return (DefWindowProc(hwnd, msg, wparam, lparam));} // end WinProc


The code never actually goes into the FD_ACCEPT bracket, and the WM_SOCKET message never fires.

Does this help?
bind() before WSAAsyncSelect()

make sure all valid handles

#define WM_SOCKET WM_APP +

Kuphryn
I moved the WSAAsyncSelect() code block to the position after the bind() code block. I also changed my #define WM_SOCKET from WM_USER + 1 to WM_APP + 1. And all the handles are valid (main_window_handle is the only handle in the program). Still, it's not working. Any other suggestions?

Also, does anyone have a copy of Richard Hallett's "How to create a non blocking server" article? Gamedev.net's copy is missing, and I can't find it on-line anywhere else (it has a forum topic devoted to discussion on the article, and the article "Programming with asynchronous sockets references it").

-Gauvir_Mucca

[Edited by - Gauvir_Mucca on June 24, 2006 1:03:21 PM]
socket() third parameter 0?

IPPROTO_TCP

Kuphryn
Advertisement
(That last post was mine, by the way).

-Gauvir_Mucca
try the following
memset() all structs to 0 before using
remove htonl(..) on INADDR_ANY
only using FD_ACCEPT on asyncSelect
listen with SOMAXCONN and not 1
also make sure it's the right window handle to asyncselect, and that it's initialized before u call asyncselect, that is the window is already created and active
LRESULT CALLBACK TestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);// Mainint WINAPI WinMain(	HINSTANCE hInstance,	HINSTANCE hPrevInstance,	LPSTR lpCmdLine,	int nCmdShow) {	WNDCLASS	wc;	HWND		hWnd;	SOCKET		s;	SOCKADDR_IN	addr;	MSG			msg;	WSADATA		wsaData;	int			iret;		// WinSock	iret = WSAStartup(0x202, &wsaData);	if(iret || wsaData.wVersion != 0x202) {		return 0;	}		// Wndclass	memset(&wc, 0, sizeof(wc));	wc.lpszClassName = "TestClass";	wc.hInstance = hInstance;	wc.lpfnWndProc = TestWndProc;	wc.hCursor = LoadCursor(NULL, IDC_ARROW);	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	if(RegisterClass(&wc) == 0) {		WSACleanup();		return 0;	}		// Window	hWnd = CreateWindow(		"TestClass",		"TestWindow",		WS_OVERLAPPEDWINDOW,		CW_USEDEFAULT,		CW_USEDEFAULT,		400,		300,		NULL,		NULL,		hInstance,		NULL	);	if(hWnd == NULL) {		WSACleanup();		return 0;	}	ShowWindow(hWnd, nCmdShow);		// Socket	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	if(s == INVALID_SOCKET) {		WSACleanup();		return 0;	}		// Async	if(WSAAsyncSelect(s, hWnd, WM_USER+1, FD_ACCEPT) != 0) {		WSACleanup();		return 0;	}		// Bind	memset(&addr, 0, sizeof(addr));	addr.sin_family = AF_INET;	addr.sin_addr.s_addr = INADDR_ANY;	addr.sin_port = htons(8888);// Port	if(bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) {		WSACleanup();		return 0;	}		// Listen	if(listen(s, SOMAXCONN) == SOCKET_ERROR) {		WSACleanup();		return 0;	}		// Loop	while(GetMessage(&msg, NULL, 0, 0)) {		TranslateMessage(&msg);		DispatchMessage(&msg);	}		// Close listening socket	closesocket(s);		// Close WinSock	WSACleanup();		return msg.wParam;}// WinMain// WndprocLRESULT CALLBACK TestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {	switch(msg) {		// Socket message		case WM_USER+1:			switch(WSAGETSELECTEVENT(lParam)) {				// Incoming connection				case FD_ACCEPT:					if(WSAGETSELECTERROR(lParam)) {						// Error					}					else {						// Connection available						SOCKET	ls = (SOCKET)wParam;						SOCKET	s;												// Accept it						s = accept(ls, NULL, 0);						if(s == INVALID_SOCKET) {							// Failure						}						else {							// Success							MessageBox(NULL, "CONNECTION ACCEPTED", "MESSAGE", MB_OK);														// Close the accepted connection after the user closes							// the message box							closesocket(s);						}					}				break;			}		break;				// Close		case WM_CLOSE:			PostQuitMessage(0);		break;	}		return DefWindowProc(hWnd, msg, wParam, lParam);}// TestWndProc

This topic is closed to new replies.

Advertisement