munou

  • タグ:
  • タグはありません
/********************************************************/
/*                                                      */
/*対話エージェントを組み込んだチャットサーバその1      */
/*起動すると80番ポートで接続を待ち受けます              */
/*使い方                                                */
/*ctrl-cキーの入力でプログラム停止                      */
/*                                                      */
/*                                                      */
/********************************************************/
/*ヘッダファイルのインクルード                          */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
//#include <sys/socket.h>
//#include <arpa/inet.h>
//#include <unistd.h>
#pragma warning(disable:4996)
#pragma warning(disable:4244)

/*記号定数の定義*/
#define SERVERPORTNUM 81 /*サーバのポート番号*/
#define MAXNUM 10/*最大接続数*/
#define MSGLENGTH 256 /*メッセージの最大長*/
#define SEED 32767/*乱数の種*/
#define LINES 15/*チャットの保存行数*/
#define MAXS 65535/*法要例文の最大数*/
#define CHARS 4/*例文検索キーのバイト数*/
#define OUTPUTFILE "2gram.txt"/*学習結果の出力ファイル*/

/*関数のプロトタイプの宣言*/
void startserver(int *serversocket);/*サーバを起動します*/
void sendtext(int cs,char *msg);/*返答メッセージの送信*/
void sendmes(int cs,char msgs[LINES][MSGLENGTH]);/*返答メッセージ作成*/
void sendhead(int cs);/*ヘッダ等の送付*/
void sendtail(int cs);/*htmlを完結させる*/
void sendbox(int cs);/*テキストボックスの送信*/
void getmes(int cs,char msgs[LINES][MSGLENGTH]);
                        /*ブラウザから入力処理*/
void decoder(char msg[],char sjismsg[]);/*漢字コードを取り出す*/
void agent(char megs[LINES][MSGLENGTH]);
                        /*対話エージェントの処理*/
int getreplydata();/*応答例文の初期化*/
void learn(char msgs[LINES][MSGLENGTH]);/*2-gramの学習*/
void searchword(int *i,char word[]);/*2-gram集から単語を探す*/
int cont(char msg[MSGLENGTH],int start);/*字種による分割*/
int iskanji(char chr);/*sjis漢字1byte目の判定*/

int rnd(int n);/*n以下の乱数を返す*/

/*外部変数*/
char reply[MAXS][MSGLENGTH];/*2-gram集*/
int replyno;/*単語数*/
/******************/
/*   main()関数   */
/******************/
int main()
{
	int serversocket;/*サーバ用ソケットディスクリプタ*/
	int clientsocket;/*クライアント用ソケットディスクリプタ*/
	struct sockaddr_in client;/*クライアントのアドレス*/
	unsigned int cl;/*クライアント処理に必要な変数*/
	char msgs[LINES][MSGLENGTH]={""};/*チャットのメッセージ*/
	WSADATA wsaData;
    SOCKET sock;

    WSAStartup(MAKEWORD(2,0), &wsaData); 
	/*応答例文の初期化*/
	replyno=getreplydata();

	/*乱数の初期化*/
	srand(SEED);

	/*サーバ側のソケット準備*/
	startserver(&serversocket);

	/*クライアントからの呼び出しへの対応*/
	while(1){
		cl=sizeof(client);
		if((clientsocket
			= accept(serversocket,(struct sockaddr *) &client,(int *)&cl))<0){
				fprintf(stderr,"accept()呼び出しエラー\n");
				exit(1);/*失敗*/}

		/*ブラウザからの入力処理*/
		getmes(clientsocket,msgs);

		/*対話エージェントの処理*/
		agent(msgs);

		/*返答メッセージの処理*/
		sendmes(clientsocket,msgs);

		/*接続終了*/
		closesocket(clientsocket);

		/*学習結果の出力*/
		if(strlen(msgs[1])>0)/*直前のメッセージが空ではない*/
			learn(msgs);/*学習処理*/
	}
	WSACleanup();
}
/***********************/
/*     learn()関数     */
/*2-garmの学習         */
/***********************/
void learn(char msgs[LINES][MSGLENGTH])
{
	FILE *fp;/*出力ファイルのファイルポインタ*/
	int start,end,i;/*配列の処理位置*/
	char word[MSGLENGTH];/*処理用文字列*/

	/*ファイル出力の準備*/
	if((fp=fopen(OUTPUTFILE,"a"))==NULL){
		fprintf(stderr,"fopen()呼び出しのエラー\n");
		exit(1);/*ファイル書き込みに失敗*/
	}

	/*2-gramを作成して学習する*/
	start=0;
	printf("学習単語\n");
	while(start<strlen(msgs[1])){
		end=cont(msgs[1],start);
		for(i=0;i<end-start;++i)/*単語のコピー*/
			word[i]=msgs[1][start+i];
		word[i]='';/*単語の終わり*/
		fprintf(fp,"%s\n",word);/*ファイル出力*/
		printf(" word:%s\n",word);
		/*内部状態の更新*/
		if(replyno<MAXS-1){
			++replyno;
			strcpy(reply[replyno],word);
		}
		start=end;/*次の単語*/
	}
	/*区切り記号を出力*/
	fprintf(fp,"\n");
	strcpy(reply[++replyno],"");
	/*出力終了*/
	fclose(fp);
}

/**********************/
/*     cont()関数     */
/*字種による分割      */
/**********************/
int cont(char msg[MSGLENGTH],int start)
{
	int i;
	int state;

	state=iskanji(msg[start]);/*字種の設定*/
	for(i=start+2;i<strlen(msg);i+=2)
		if(state!=iskanji(msg[i]))break;
	return i;
}

/*************************/
/*     iskanji()関数     */
/*sjis漢字1byte目の判定  */
/*************************/
int iskanji(char chr)
{
	if((unsigned char)chr>=0x88)return 1;
	else return 0;
}

/******************************/
/*     getreplydata()関数     */
/*応答例文の初期化            */
/******************************/
int getreplydata()
{
	int lineno=0;/*読み込んだ行数*/
	int chrno=0;/*書き込んだ文字の位置*/
	int chr;/*読み込んだ文字*/

	while(((chr=getchar())!=EOF)&&(lineno<MAXS)){
		if(chr=='\n')/*改行*/
			chr='';/*文字列の終わりとする*/
		reply[lineno][chrno]=chr;/*文字をセット*/
		++chrno;/*次の文字*/
		if(chrno>(MSGLENGTH-10)){/*長さを超過*/
			reply[lineno][chrno]='';
			chrno=0;
			++lineno;
		}
		else if(chr==''){/*文字列が終端*/
			chrno=0;
			++lineno;
		}
	}
	reply[lineno][chrno]='';
	if(lineno==0){/*2-gram集がない*/
		fprintf(stderr,"2-gram集がありません。\n");
		exit(1);
	}
	printf("単語集%d\n",lineno);

	return lineno;/*2-gram集の例文数を返す*/
}
/**************************/
/*     setreply()関数     */
/*応答処理                */
/**************************/
void setreply(char msgs[LINES][MSGLENGTH])
{
	static int i=0;/*例文を選択するための変数*/
	int ptr;/*文字の位置*/
	int length;/*直前の発話の長さ*/
	char word[MSGLENGTH];/*直前の発話から切り出した単語*/
	int counter;/*例文検索の回数を数える変数*/

	/*直前の発話から適当な部分を切り出す*/
	ptr=rnd(strlen(msgs[1]))/2*2;/*切り出し位置決定*/
	strncpy(word,&(msgs[1][ptr]),CHARS);/*単語の切り出し*/
	word[CHARS]='';/*文字列の終わり*/
	/*2-gram検索のためのキーワードを表示*/
	printf("keyword:%s\n",word);

	/*2-gram集から、上記を含む文を探す*/
	strcpy(msgs[0],">");
	searchword(&i,word);
	strcat(msgs[0],word);/*出力文字列の単語を連結*/
	if(strlen(reply[i])<=0)return;/*空の単語*/

	/*2-gramの連鎖処理*/
	while(strlen(msgs[0])<MSGLENGTH){
		printf("連鎖処理 msgs[0]:%s reply[]:%s\n",msgs[0],reply[i]);
		strcat(msgs[0],reply[i]);/*出力文字列に連鎖する単語を連結*/
		strcpy(word,reply[i]);
		++i;if(i>replyno)i=0;
		if(strlen(reply[i])<=0)break;/*空の単語*/
		searchword(&i,word);/*次の連鎖を検索*/
	}
}

/**************************/
/*     searchword関数     */
/*2-gram集から単語を探す  */
/**************************/
void searchword(int *i,char word[])
{
	int counter;/*例文検索の回数を数える変数*/

	/*2-gram集から、上記を含む分を探す*/
	counter=0;
	while(counter<=replyno){
		if(strstr(reply[*i],word)!=NULL){
			strcpy(word,reply[*i]);
			++(*i);/*次の検索に備える*/
			return;/*単語が見つかった*/
		}
		++(*i);
		if(*i>replyno)*i=0;
		++counter;
	}
	/*なければ、適当に単語を返す*/
	*i=rnd(replyno-1);
	strcpy(word,reply[*i]);
	++(*i);/*次の検索に備える*/
}

/*************************/
/*      agent()関数      */
/*対話エージェントの処理 */
/*************************/
void agent(char msgs[LINES][MSGLENGTH])
{
	int i;
	int select;

	/*msgs[][]の更新*/
	for(i=LINES-1;i>0;--i)strcpy(msgs[i],msgs[i-1]);
	/*発話*/
    if(strlen(msgs[1])>0){/*直前のメッセージが空でない*/
		setreply(msgs);
		printf("%s\n",msgs[0]);
	}
}

/****************************/
/*       getmes()関数       */
/*ブラウザから入力処理      */
/****************************/
void getmes(int cs,char msgs[LINES][MSGLENGTH])
{
	char prev1,prev2,prev3;/*リクエスト終了判定用変数*/
	char msg[MSGLENGTH];/*メッセージのバッファ*/
	int i;

	prev1=prev2='';
	i=0;
	while(((recv(cs,&msg[i],1,0))>0)&&(i<MSGLENGTH-1)){/*1文字ずつ読み取る*/
		if((msg[i]=='\n')&&(prev1='\r'))break;
		                       /*改行が送られてきたら読み取り終了*/
		prev2=prev1;prev1=msg[i];/*判定の準備*/
		++i;
	}
	msg[i]='';/*文字列の終わり*/
	if(strchr(msg,'=')!=NULL){/*入力文字列が送られてきた*/
		/*msgs[][]の更新*/
		for(i=LINES-1;i>0;--i)strcpy(msgs[i],msgs[i-1]);
		decoder(strchr(msg,'='),msgs[0]);
		printf("%s\n",msgs[0]);/*サーバ画面に文字列を出力*/
	}

	prev1=prev2=prev3='';
	while(((recv(cs,msg,1,0))>0)&&(i<MSGLENGTH-1)){
		                         /*1文字ずつ読み取る*/
		if((msg[0]=='\n')&&(prev1=='\r')&&(prev2=='\n'))break;
		                         /*空行が送られてきたら読み飛ばし終了*/
		prev3=prev2;prev2=prev1;prev1=msg[0];/*判定の準備*/
	}
}
/*************************/
/*    decoder()関数     */
/*漢字コードを取り出す   */
/*************************/
void decoder(char msg[],char sjismsg[])
{
	int i=1,j=0;
	char hexch[3];/*2行の16進数(文字表現)*/

	while(msg[i]!=' '){/*エンコードされたsjisコードを取り出す*/
		if(i>MSGLENGTH-2)break;/*文字列の長さの上限*/
		else if(msg[i]=='+'){
			sjismsg[j]=' ';/*半角空白*/
			++i;
		}
		else if(msg[i]=='%'){/*エンコードされた全角文字*/
			++i;
		hexch[0]=msg[i];
		hexch[1]=msg[i+1];
		hexch[2]='';
		sjismsg[j]=strtol(hexch,NULL,16);
		++i;++i;
		}
		else {/*エンコードされていない文字*/
			sjismsg[j]=msg[i];
			++i;
		}
		++j;
	}
	sjismsg[j]='';/*文字列の終わり*/
}

/*************************/
/*     sendmes()関数     */
/*返答メッセージ作成     */
/*************************/
void sendmes(int cs,char msgs[LINES][MSGLENGTH])
{
	int i;

	/*htmlのヘッダ等の送付*/
	sendhead(cs);

	/*テキストボックスの送信*/
	sendbox(cs);

	/*これまでのデータ送信*/
	for(i=0;i<LINES;++i){
		sendtext(cs,msgs[i]);
		sendtext(cs,"<br>\r\n");
	}

	/*htmlを結合させる*/
	sendtail(cs);

}

/*************************/
/*     sendbox()関数     */
/*テキストボックスの送信 */
/*************************/
void sendbox(int cs)
{
	sendtext(cs,
		"<form action=\"cgi\"method=\"get\">");
	sendtext(cs,
		"<input type=\"submit\"value=\"send\">\r\n");
	sendtext(cs,
		"<input type=\"text\"name=\"text\"size=\"80\"maxlength=\"60\">\r\n");
	sendtext(cs,"</form>\r\n");
}

/**************************/
/*     sendhead()関数     */
/*ヘッダ等の送付          */
/**************************/
void sendhead(int cs)
{
	sendtext(cs,
		"<html><head><title>chat server</title></head><body>\r\n");
}

/**************************/
/*     sendtail()関数     */
/*htmlを完結させる        */
/**************************/
void sendtail(int cs)
{
	sendtext(cs,"</body></html>\r\n\r\n");
}

/***************************/
/*     sendtext()関数      */
/*返答メッセージの送信     */
/*および画面表示           */
/***************************/
void sendtext(int cs,char *msg)
{
	send(cs,msg,strlen(msg),0);/*クライアントへの送信*/
}

/***************************/
/*     rnd()関数           */
/*n未満の乱数を返す        */
/***************************/
int rnd(int n)
{
	int rndno;/*生成する乱数*/

	while((rndno=(double)rand()/RAND_MAX*n)==n);

	return rndno;
}

/***************************/
/*     startserver()関数   */
/*サーバを起動します       */
/***************************/
void startserver(int *serversocket)
{
	struct sockaddr_in serveradd;/*サーバのアドレス*/

	/*サーバ側のソケットの準備*/
	if((*serversocket=
		socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0){
			fprintf(stderr,"socket()呼び出しのエラー\n");exit(1);
			/*準備失敗*/}
	memset(&serveradd,0,sizeof(serveradd));
	serveradd.sin_family=AF_INET;
	serveradd.sin_addr.s_addr=htonl(INADDR_ANY);
	serveradd.sin_port=htons(SERVERPORTNUM);
	if(bind(*serversocket,(struct sockaddr *)&serveradd,
		sizeof(serveradd))<0){
			fprintf(stderr,"bind()呼び出しのエラー\n");exit(1);
			/*準備失敗*/}
	/*接続を待ち受ける*/
	if(listen(*serversocket,MAXNUM)<0){
		fprintf(stderr,"listen()呼び出しのエラー\n");exit(1);
		/*準備失敗*/}
}