猫C++を読み終えてから、次のステップ

taketoshi
記事: 222
登録日時: 14年前
住所: 日本国

猫C++を読み終えてから、次のステップ

投稿記事 by taketoshi » 14年前

CODE:

#include"Prehead.h"
#include"log.h"

#define MAX_MEMBER 3
//グローバル変数
HINSTANCE hInstance;
//メインウインドウハンドル
HWND hWnd;
HWND hEdit[4];
HWND hStart,hSend,hCut;
HICON hIco;

////////////////////////////////////////////////////////////////////////
//エラー表示関数
//一般関数
////////////////////////////////////////////////////////////////////////
int viewerror(char *szError){
	char szBuff[256];
	wsprintf(szBuff,"エラー = %s",szError);
	MessageBox(NULL,szBuff,"エラー",MB_OK);
	return 0;
}

////////////////////////////////////////////////////////////////////////
//ソケットとクライアント情報を管理する構造体
//
////////////////////////////////////////////////////////////////////////
typedef struct{
	int nId;			//構造体の要素数+1
	SOCKADDR_IN from;	//クライアント情報
	SOCKET s;			//ソケット
}DATA;

////////////////////////////////////////////////////////////////////////
//ソケットクラス定義
//
////////////////////////////////////////////////////////////////////////
class server{
private:
	WSADATA wsaData;
	static  SOCKET listen_s;
	u_short uport;
	int nAsync,nFromlen;
	SOCKADDR_IN sockaddr_in;
	char szOutBuff[384];
	char szInfoBuff[512];
	int nRet,i;
	static int nConnectCount;
	static DATA MemData[MAX_MEMBER];
public:
	server();					//コンストラクタ
	~server();					//デストラクタ
	BOOL WSAStart();			//WSAスタートアップ
	int CreateListen(HWND);		//リスンソケット生成、非同期化
	BOOL connectaccept();		//クライアントの接続を受け入れる関数(FD_ACCEPT)
	int cut();					//切断する関数
	int closeserver(WPARAM);	//サーバー切断関数
	int read(WPARAM);			//データ受信
	int senddata(WPARAM);		//データ送信
};

//スタティック変数の宣言
SOCKET server::listen_s;
int server::nConnectCount = 0;
DATA server::MemData[MAX_MEMBER];

////////////////////////////////////////////////////////////////////////
//コンストラクタ
////////////////////////////////////////////////////////////////////////
server::server(){
}

////////////////////////////////////////////////////////////////////////
//デストラクタ
////////////////////////////////////////////////////////////////////////
server::~server(){
}

////////////////////////////////////////////////////////////////////////
//WSAStartup関数
//戻り値:BOOL
////////////////////////////////////////////////////////////////////////
BOOL server::WSAStart(){
	if(WSAStartup(MAKEWORD(1,1),&wsaData)){
		viewerror("WSAスタートアップエラー");
		return false;
	}
	return TRUE;
}

////////////////////////////////////////////////////////////////////////
//非同期化からListenソケットを生成するまでの関数
//戻り値:int
//引数:非同期化メッセージを受信するウインドウハンドル
////////////////////////////////////////////////////////////////////////
int server::CreateListen(HWND hDlg){

	char szBuffer[384];

	GetWindowText(hEdit[0],szBuffer,sizeof(szBuffer));
	listen_s = socket(AF_INET,SOCK_STREAM,0);
	uport = atoi(szBuffer);
	if(listen < 0){
		viewerror("リスンソケット生成エラー");
		WSACleanup();
		return -2;
	 }else{
		wsprintf(szInfoBuff,"ポート番号:%d\r\n",uport);
		SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
		EnableWindow(hStart,false);
	}

	nAsync = WSAAsyncSelect(listen_s,hDlg,MY_MSG, FD_ACCEPT | FD_CLOSE | FD_READ);

	if(nAsync != 0){
		viewerror("非同期化エラー");
		closesocket(listen_s);
		return -2;
	}

	memset(&sockaddr_in,0,sizeof(SOCKADDR_IN));
	sockaddr_in.sin_family = AF_INET;
	sockaddr_in.sin_port = htons(uport);
	sockaddr_in.sin_addr.s_addr = INADDR_ANY;

	if(bind(listen_s,(SOCKADDR *)&sockaddr_in,sizeof(sockaddr_in)) == SOCKET_ERROR)
	{
		viewerror("バインドエラー");
		closesocket(listen_s);
		return -3;
	}

	if(listen(listen_s,0) == SOCKET_ERROR)							//リスンソケットを廃棄しないので無尽蔵に接続できる
	{
		viewerror("リスンエラー");
		closesocket(listen_s);
		return -4;
	}else{
		strcpy(szInfoBuff,"リスンソケット生成接続待機します\r\n");
		SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
		EnableWindow(hCut,true);
	}
	return TRUE;
}

////////////////////////////////////////////////////////////////////////
//接続許可を出す関数
//戻り値:int
////////////////////////////////////////////////////////////////////////
BOOL server::connectaccept(){
	if(nConnectCount == MAX_MEMBER){
		strcpy(szInfoBuff,"これ以上接続できません\r\n");
		SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
		wsprintf(szInfoBuff,"%d",nConnectCount);
		SetWindowText(hEdit[2],szInfoBuff);
		accept(listen_s,NULL,0);									//ブロッキング回避の読み捨て
		return false;
	}else{
		nFromlen = sizeof(SOCKADDR_IN);
		for(i = 0;i <= MAX_MEMBER;++i){
				if(MemData[i].nId == 0){
					MemData[i].nId = i+1;
					MemData[i].s = accept(listen_s,(sockaddr *)&MemData[i].from,&nFromlen);
					if(MemData[i].s == INVALID_SOCKET){
						strcpy(szInfoBuff,"接続ソケット生成エラー\r\n");
						SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
						return false;
					}else{
						wsprintf(szOutBuff,"%s",inet_ntoa(MemData[i].from.sin_addr));
						wsprintf(szInfoBuff,"%sが接続してきました\r\n",szOutBuff);
						SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
						++nConnectCount;
						wsprintf(szInfoBuff,"%d",nConnectCount);
						SetWindowText(hEdit[2],szInfoBuff);
						EnableWindow(hSend,true);
						return false;
					}
				}
			}
	}
	return true;
}

////////////////////////////////////////////////////////////////////////
//切断関数
//戻り値:int
////////////////////////////////////////////////////////////////////////
int server::cut(){
	for(i = 0;i < MAX_MEMBER;++i){
		shutdown(MemData[i].s,SD_BOTH);
		closesocket(MemData[i].s);
	}
	for(i = 0;i < MAX_MEMBER;++i){
		memset(&MemData[i].nId,0,sizeof(int));
		memset(&MemData[i].from,0,sizeof(SOCKADDR_IN));
		memset(&MemData[i].s,0,sizeof(SOCKET));
	}
		closesocket(listen_s);
		EnableWindow(hStart,true);
		nConnectCount = 0;
		EnableWindow(hSend,false);
		SetWindowText(hEdit[2],"0");
		EnableWindow(hCut,false);

	return 0;
}
////////////////////////////////////////////////////////////////////////
//サーバークローズ関数
//戻り値:int
////////////////////////////////////////////////////////////////////////
int server::closeserver(WPARAM wParam){

	char szBuffer[256];
	for(i = 0;i < MAX_MEMBER;++i){
			if((SOCKET)wParam == MemData[i].s){
				wsprintf(szInfoBuff,"%sが切断しました\r\n",inet_ntoa(MemData[i].from.sin_addr));
				shutdown(MemData[i].s,SD_BOTH);
				closesocket(MemData[i].s);
				SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
				nConnectCount--;
				wsprintf(szBuffer,"%d",nConnectCount);
				SetWindowText(hEdit[2],szBuffer);
				memset(&MemData[i].nId,0,sizeof(int));
				memset(&MemData[i].from,0,sizeof(SOCKADDR_IN));
				memset(&MemData[i].s,0,sizeof(SOCKET));
				if(nConnectCount == 0)
					EnableWindow(hSend,false);
				for(i = 0;i < MAX_MEMBER;++i){//接続している他のクライアントに切断通知を送信
					if((SOCKET)wParam != MemData[i].s && MemData[i].nId != 0){
						send(MemData[i].s,szInfoBuff,(int)strlen(szInfoBuff),0);
					}
				}
			}
		}
	return 0;
}

////////////////////////////////////////////////////////////////////////
//受信関数
//戻り値:int
////////////////////////////////////////////////////////////////////////
int server::read(WPARAM wParam){
	char szBuffer[256];
		for(i = 0;i < MAX_MEMBER;++i){
			if((SOCKET)wParam == MemData[i].s){
				wsprintf(szOutBuff,"%s",inet_ntoa(MemData[i].from.sin_addr));
			}
		}
		for(i = 0;i < MAX_MEMBER;++i){
			if((SOCKET)wParam == MemData[i].s){	//受信ソケットの照合作業ですこの作業をやらないと何故か接続オーバーしたクライアントからゴミを送りつけられる。必ずソケットは選択受信すること。
				memset(szBuffer,0,sizeof(szBuffer));
				nRet =recv(MemData[i].s,szBuffer,sizeof(szBuffer),0);
				szBuffer[nRet] = '\0';
				wsprintf(szInfoBuff,"%s:%s\r\n",szOutBuff,szBuffer);
				SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
				for(i = 0;i < MAX_MEMBER;++i){//サーバーにきたクライアントの文章を他のクライアントに転送
					if((SOCKET)wParam != MemData[i].s)
						send(MemData[i].s,szInfoBuff,(int)strlen(szInfoBuff),0);
				}
			}
		}
		return 0;
}

////////////////////////////////////////////////////////////////////////
//送信関数
//戻り値:int
////////////////////////////////////////////////////////////////////////
int server::senddata(WPARAM wParam){
	char szBuffer[256];
		GetWindowText(hEdit[3],szBuffer,sizeof(szBuffer));
		if(strcmp(szBuffer,"") == 0){
			strcpy(szBuffer,"空白は入力できません\r\n");
			SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szBuffer);
			return false;
		}
		wsprintf(szInfoBuff,"Server:%s\r\n",szBuffer);
		SendMessage(hEdit[1],EM_REPLACESEL,1,(LPARAM)szInfoBuff);
		CreateLog(szBuffer,false);
		for(i = 0;i < MAX_MEMBER;++i){
			if(MemData[i].nId != 0){
				send(MemData[i].s,(char *)szInfoBuff,(int)strlen(szInfoBuff),0);
			}
		}
		SetWindowText(hEdit[3],"");
		return 0;
}

BOOL CALLBACK DlgProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{
	server Obj_server;
	int nEvent;

	switch(msg)
	{
	case WM_INITDIALOG:
		SendMessage(hDlg,WM_SETICON,(WPARAM)ICON_BIG,(LPARAM)hIco);

		Obj_server.WSAStart();

		hEdit[0] = GetDlgItem(hDlg,IDC_EDIT1);	//ポート番号
		hEdit[1] = GetDlgItem(hDlg,IDC_EDIT2);	//情報ウインドウ
		hEdit[2] = GetDlgItem(hDlg,IDC_EDIT3);	//接続数
		hEdit[3] = GetDlgItem(hDlg,IDC_EDIT4);	//送信ボックス
		SendMessage(hEdit[3],EM_SETLIMITTEXT,(WPARAM)256,0);
		hStart = GetDlgItem(hDlg,IDC_START);
		hSend = GetDlgItem(hDlg,IDC_SENDDATA);
		hCut = GetDlgItem(hDlg,IDC_CUT);
		SetWindowText(hEdit[0],"8000");
		SetWindowText(hEdit[2],"0");
		EnableWindow(hSend,false);
		EnableWindow(hCut,false);
		return false;

	case WM_CLOSE:
		EndDialog(hDlg,0);
		return false;

	case WM_COMMAND:
		switch(LOWORD(wParam)){
		case IDC_END:
			EndDialog(hDlg,0);
			return false;

		case IDC_START:
			Obj_server.CreateListen(hDlg);
			return false;

		case IDC_SENDDATA:
			Obj_server.senddata(wParam);
			return false;
		case IDC_CUT:
			Obj_server.cut();
			return false;
		}
		case MY_MSG:
			nEvent = WSAGETSELECTEVENT(lParam);
			switch(nEvent)
			{
				case FD_ACCEPT:	//WPARAMが通知をしてきたソケット
					Obj_server.connectaccept();
					break;
				case FD_CLOSE:
					Obj_server.closeserver(wParam);
					break;
				case FD_READ:
					Obj_server.read(wParam);
					break;
			}
	default:
		return false;
	}
	return true;
}

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
	//Global変数にコピー
	hInstance = hInst;

	hIco = (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_ICON1),IMAGE_ICON,0,0,
				LR_SHARED|LR_DEFAULTCOLOR);
	if(hIco == NULL)
				MessageBox(NULL,"アイコン読み取りエラー","確認",MB_OK);
	DialogBox(hInstance,MAKEINTRESOURCE(Client),NULL,&DlgProc);
	WSACleanup();
	return 0;
}

以前書いた複数接続のTCPサーバーの機能をクラス化してみました。
全部オブジェクト指向で書くならば、hWndを生成するクラスを親として、そこにWinsock機能を子クラスとして派生させるんですかね・・?
この書き方って中途半端???

この前書いた、ODBCのクラスと合わせて。ネットワークデータベースを構築する基礎知識は備わったのかな。と思います。
そして、DBの知識を更に深めるべく秋葉原に用事で寄る機会があったのでSQLServer2008の解説書(入門書)を一冊買って来ました。



しかーし、C++の参考書も併せて買おうかと思ったのですが、何を勉強していいやら判りませんでした。
STLとか便利だなーと思うのですが、非常に難解な参考書ばっかり並んでいました。


まだ次に進むのは早いかなぁ、もう少し猫C++を読み解いたほうがいいかなぁ。

コメントはまだありません。