Problems with Asynchronous Socket
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
Here is the relevant header information:
Here is the function that starts listening for connections:
Here is the message handler code:
The code never actually goes into the FD_ACCEPT bracket, and the WM_SOCKET message never fires.
Does this help?
#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
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]
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]
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
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
Popular Topics
Advertisement
Recommended Tutorials
Advertisement