#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;
}
全部オブジェクト指向で書くならば、hWndを生成するクラスを親として、そこにWinsock機能を子クラスとして派生させるんですかね・・?
この書き方って中途半端???
この前書いた、ODBCのクラスと合わせて。ネットワークデータベースを構築する基礎知識は備わったのかな。と思います。
そして、DBの知識を更に深めるべく秋葉原に用事で寄る機会があったのでSQLServer2008の解説書(入門書)を一冊買って来ました。
しかーし、C++の参考書も併せて買おうかと思ったのですが、何を勉強していいやら判りませんでした。
STLとか便利だなーと思うのですが、非常に難解な参考書ばっかり並んでいました。
まだ次に進むのは早いかなぁ、もう少し猫C++を読み解いたほうがいいかなぁ。