非同期接続型ソケット通信プログラミング
眠すぎるけど、気合で少しは勉強しよう。
名前はいかめしいが、ようするに、チャットを作りたいんですね。インターネットでする分には、そういうネットワーク周りは、全部httpサーバがやってくれますが、C++で作ろうと思ったら、そういう低階層のところまでこちらで制御してやらんので、大変。
これでも、TCP/IP等の知識はなくても作ってくれるので、簡単らしい。
なんというか、ハードウェアエンジニアってすげーと思います。
とりあえず、備忘録
/** コントロールを使える/使えなくする. *@param HWND リソースのコントロールID *@param BOOL FALSEでつかなくなる。 */ EnableWindow( HWND hSendBtn, BOOL FALSE);
猫でもわかるネットワークプログラミングを参考に、ひたすら打ち続けた。
本当に誤字が気になる。セミコロンの忘れもけしからんが、引数の数間違いや、カンマの打ち忘れは許せません。
明日学校に残れたらクライアント側も作る予定なので、ここに今日書いたコードを載せておこう。完全にBlogが備忘録扱い.
// wserver.cpp : アプリケーション用のエントリ ポイントの定義 // #define WIN32_LEAN_AND_MEAN #include "stdafx.h" #include#include #include #include "resource.h" BOOL InitInstance(); LRESULT CALLBACK ViewW( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ); LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); int mystream( HWND hDlg, u_short uport ); SOCKET s; const char ClassName[]="Hatena_Sample"; HWND D1; HINSTANCE hInst; ATOM MyRegisterClass(); BOOL bSOCKET_S = FALSE, bSOCKET_LISTEN = FALSE;; #define MY_MSG ( WM_USER + 1) SOCKET listen_s; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { MSG msg; // TODO: この位置にコードを記述してください。 WSADATA wsaData; if ( WSAStartup( MAKEWORD(1,1), &wsaData ) ) { MessageBox(NULL, "初期化失敗", "Error", MB_OK | MB_ICONEXCLAMATION ); WSACleanup(); return -1; } hInst = hInstance;//GetModuleHandle(NULL); if(!MyRegisterClass()){ return 0; } // アプリケーションの初期化を行います: if( !InitInstance() ) { ExitProcess(0); return 0; } while( GetMessage(&msg, NULL, 0, 0) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } ExitProcess(msg.wParam); if ( WSACleanup() != 0 ) { MessageBox(NULL, "WSACleanupエラーです", "Error", MB_OK ); } MessageBox(NULL, "終了します", "終了", MB_OK ); return 0; } BOOL InitInstance() { HWND hWnd; hWnd = CreateWindow(ClassName,"", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, hInst, NULL); // ShowWindow( hWnd, 1 ); メインWindowは表示しない if( !hWnd ) { return FALSE; } DialogBox(hInst, (LPCTSTR)IDD_FORMVIEW, hWnd, (DLGPROC)ViewW); return TRUE; } LRESULT CALLBACK ViewW( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { static HWND hStart, hInfo, hSendBtn; static u_short port; BOOL bSuccess; int nRet, nEvent; char szBuf[1024]; static char szAllBuf[1024 * 10 ] = ""; SOCKADDR from; int fromlen, nError, nAsync; switch( message ) { case WM_INITDIALOG: //タスクバーに表示されるようにする ::SetWindowLong(hDlg, GWL_EXSTYLE, ::GetWindowLong(hDlg, GWL_EXSTYLE) | WS_EX_APPWINDOW); //アイコンを登録してみる SendMessage (hDlg, WM_SETICON, ICON_BIG, (LPARAM)(HICON) LoadIcon(hInst, (LPCTSTR)IDI_ICON1)); SendMessage (hDlg, WM_SETICON, ICON_SMALL, (LPARAM)(HICON) LoadIcon(hInst, (LPCTSTR)IDI_ICON1)); D1=hDlg; hStart = GetDlgItem( hDlg, IDC_START); hInfo = GetDlgItem( hDlg, IDC_INFO ); hSendBtn = GetDlgItem( hDlg, IDC_SENDBTN ); EnableWindow( hSendBtn, FALSE ); return TRUE; case WM_COMMAND: if( LOWORD(wParam) == IDC_BUTTON1 ) { // MessageBox(NULL, "終了が押下", "IDC_START", MB_OK ); if ( bSOCKET_S ) { nRet = shutdown( s, SD_BOTH ); if ( nRet == SOCKET_ERROR ) { MessageBox( hDlg, "シャットダウン失敗", "Error", MB_OK ); } else { MessageBox( hDlg, "シャットダウン成功", "shutdown", MB_OK ); } if ( closesocket( s ) ) { MessageBox( hDlg, "ソケットクローズ失敗", "Error", MB_ICONEXCLAMATION | MB_OK ); } } if ( bSOCKET_LISTEN ) { if ( closesocket( listen_s ) ) { MessageBox( hDlg, "リスンソケットクローズ失敗", "Error", MB_ICONEXCLAMATION | MB_OK ); } } EndDialog(hDlg, LOWORD(wParam)); PostQuitMessage( 0 ); return TRUE; } if ( LOWORD( wParam ) == IDC_START ) { // MessageBox(NULL, "IDC_STARTが押下", "IDC_START", MB_OK ); port = (u_short)GetDlgItemInt(hDlg, IDC_PORT, &bSuccess, FALSE); if ( mystream( hDlg, port ) == 0 ) { EnableWindow( hStart, FALSE ); } return TRUE; } if ( LOWORD( wParam ) == IDC_SENDBTN ) { //MessageBox(NULL, "IDC_SENDBTNが押下", "IDC_START", MB_OK ); GetDlgItemText( hDlg, IDC_SEND, szBuf, (int)sizeof( szBuf ) ); nRet = send( s, szBuf, (int)strlen(szBuf), 0 ); strcat( szAllBuf, "Server:"); strcat(szAllBuf, szBuf); strcat(szAllBuf, "\r\n"); SetDlgItemText(hDlg, IDC_INFO, szAllBuf ); SendMessage( hInfo, EM_LINESCROLL, 0, Edit_GetLineCount( hInfo )); SetDlgItemText( hDlg, IDC_SEND, ""); SetFocus( GetDlgItem( hDlg, IDC_SEND )); return TRUE; } if ( LOWORD( wParam ) == MY_MSG ) { nEvent = WSAGETSELECTEVENT( lParam ); switch ( nEvent ) { case FD_CLOSE: MessageBox(hDlg, "クライアントが切断してきました\n", "再待ち受けします", MB_OK ); EnableWindow( hSendBtn, FALSE ); closesocket( s ); bSOCKET_S = FALSE; mystream( hDlg, port ); return TRUE; case FD_READ: nRet = recv( s, szBuf, (int)sizeof(szBuf) -1 , 0 ); if ( nRet == SOCKET_ERROR ) { MessageBox( hDlg, "recvエラー", "error", MB_OK ); return FALSE; } szBuf[nRet] = '\0'; strcat( szAllBuf, "Client:"); strcat( szAllBuf, szBuf ); strcat( szAllBuf, "\r\n"); SetDlgItemText( hDlg, IDC_INFO, szAllBuf ); SendMessage( hInfo, EM_LINESCROLL, 0, Edit_GetLineCount( hInfo )); return TRUE; case FD_ACCEPT: memset( &from, 0, sizeof( SOCKADDR )); fromlen = sizeof( from ); s = accept( listen_s, (SOCKADDR *)&from, &fromlen ); if ( s == INVALID_SOCKET ) { nError = WSAGetLastError(); if ( nError != WSAEWOULDBLOCK ) { switch( nError ) { case WSANOTINITIALISED: MessageBox( hDlg, "WSANOTINITIALISED", "Error", MB_OK ); break; case WSAENETDOWN: MessageBox( hDlg, "WSAENETDOWN", "Error", MB_OK ); break; case WSAEFAULT: MessageBox( hDlg, "WSAEFAULT", "Error", MB_OK ); break; case WSAEINTR: MessageBox( hDlg, "WSAEINTR", "Error", MB_OK ); break; case WSAEINPROGRESS: MessageBox( hDlg, "WSAEINPROGRESS", "Error", MB_OK ); break; case WSAEINVAL: MessageBox( hDlg, "WSAEINVAL", "Error", MB_OK ); break; case WSAEMFILE: MessageBox( hDlg, "WSAEMFILE", "Error", MB_OK ); break; case WSAENOBUFS: MessageBox( hDlg, "WSAENOBUFS", "Error", MB_OK ); break; case WSAENOTSOCK: MessageBox( hDlg, "WSAENOTSOCK", "Error", MB_OK ); break; case WSAEOPNOTSUPP: MessageBox( hDlg, "WSAEOPNOTSUPP", "Error", MB_OK ); break; default: MessageBox( hDlg, "不明のエラー", "Error", MB_OK ); break; } MessageBox( hDlg, "accept error", "Error", MB_OK ); closesocket( listen_s ); bSOCKET_LISTEN = FALSE; return TRUE; } } if ( closesocket( listen_s ) != 0 ) { MessageBox( hDlg, "Error", "Error", MB_OK ); return TRUE; } bSOCKET_LISTEN = FALSE; bSOCKET_S = TRUE; nAsync = WSAAsyncSelect( s, hDlg, MY_MSG, FD_CLOSE | FD_READ ); if ( nAsync != 0 ) { MessageBox( hDlg, "非同期化失敗", "Error", MB_OK | MB_ICONEXCLAMATION ); closesocket( s ); bSOCKET_S = FALSE; return TRUE; } EnableWindow( hSendBtn, TRUE ); return TRUE; } return FALSE; } break; } return FALSE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch( message ) { case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } ATOM MyRegisterClass() { WNDCLASS wcex; wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInst; wcex.hIcon = LoadIcon(hInst, (LPCTSTR)IDI_ICON1); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = ClassName; return RegisterClass( &wcex ); } #define MY_MSG ( WM_USER + 1) int mystream( HWND hDlg, u_short uport ) { SOCKADDR_IN saddr; int nAsync; listen_s = socket( AF_INET, SOCK_STREAM, 0 ); //listen_s はSOCKET if ( listen_s < 0 ) { if ( WSAGetLastError() != WSAEWOULDBLOCK ) { MessageBox( hDlg, "ソケットオープンエラー", "Error", MB_OK | MB_ICONEXCLAMATION ); return -1; } } else { MessageBox( NULL, "ソケットオープンしました", "socket成功", MB_OK ); } bSOCKET_LISTEN = TRUE; // bSOCKET_LISTEN はBOOL nAsync = WSAAsyncSelect( listen_s, hDlg, MY_MSG, FD_ACCEPT ); if ( nAsync != 0 ) { MessageBox( hDlg, "非同期化失敗1", "Error", MB_OK | MB_ICONEXCLAMATION ); closesocket( listen_s ); bSOCKET_LISTEN = FALSE; return -2; } memset( &saddr, 0, sizeof( SOCKADDR_IN )); saddr.sin_family = AF_INET; saddr.sin_port = htons(uport); saddr.sin_addr.s_addr = INADDR_ANY; if ( bind( listen_s, (SOCKADDR *)&saddr, sizeof(saddr)) == SOCKET_ERROR ) { MessageBox( hDlg, "bind Error\n", "別のポート番号でもう一度試してみてください。", MB_OK ); closesocket( listen_s ); bSOCKET_LISTEN = FALSE; return -3; } if ( listen( listen_s, 0 ) == SOCKET_ERROR ) { if ( WSAGetLastError() != WSAEWOULDBLOCK ) { MessageBox( hDlg, "listen Error", "Error", MB_OK ); closesocket( listen_s ); bSOCKET_LISTEN = FALSE; return -4; } } else { MessageBox( hDlg, "クライアントの接続待ちです", "OK", MB_OK ); } return 0; }