• 検索結果がありません。

通信プログラムの試作ーーー UDP を用いたじゃんけんゲームシステム ーーーー裘彬濱 南山大学情報理工学部 ソフトウェア工学科青山研究室

N/A
N/A
Protected

Academic year: 2021

シェア "通信プログラムの試作ーーー UDP を用いたじゃんけんゲームシステム ーーーー裘彬濱 南山大学情報理工学部 ソフトウェア工学科青山研究室"

Copied!
9
0
0

読み込み中.... (全文を見る)

全文

(1)

    

通信プログラムの試作ーーー

  

UDP

を用いたじゃんけんゲームシステム

    

         ーーーー裘彬濱

      

南山大学 情報理工学部 

       ソフトウェア工学科 青山研究室

(2)

1:UDP を用いたじゃんけんゲームシステムの概要

●本システムは通信プロトコル UDP を用いた簡単なじゃんけんゲームシス

テムであり、単一のユーザ(クライアント)が参加し、パソコン(サーバ)

とじゃんけんゲームするシステムである。

●本システムはユーザがゲームに参加できる時間を制限しており、制限時間

にオーバーすると、サーバが止まるようになっている。

●本システムは優勝条件を定めており、優勝条件を満たした側に優勝者にな

り、ゲームを終了させる。

2:

●応用プロトコルの説明(通信順)

C   S

|   | |--- 開始 --->| (UDP の開始メッセージ) |  | |<-ゲーム参加要請--| |   | |   | |--- 参加/不参加-->| (じゃんけんの手、推定した数字) | | |<---- 応答 ---| (結果) | | | | (以後くりかえし) | | |        | |<---- 終了 ---| (優勝/制限時間オーバーしたら、UDP の終了メッセージ) | | time V V

●応用プロトコルの説明(メッセージ形式)

メッセージは簡単な文字列とする、区切りに CRLF を使い、この単位で送受

信する。

<1>クライアントからサーバ(コマンド/要求)

開始メッセージ CRLF ー→最初にクライアントからの開始メッセージが1文

字でなくてもいいが、メッセージの内容が重要ではないので、1文字でデー

タにした。

参加/不参加 CRLF ー→参加は y、不参加は n

(3)

手/終了命令 CRLF ー→手はグー(r)チョキ(s)パー(p)で、ゲーム終了は q で、

処理が簡単になる。

<2>サーバからクライアント(応答)

OK SP 説明文字列 CRLF

NG SP 説明文字列 CRLF

説明文字列は簡潔なものにする

3:プログラム処理の流れの説明

クライアント サーバ

sock = socket() ssock= socket()

bind(ssock,,) -- 受付ポート設定    ループ始め    一回目    send(sock) ---> recv(sock,,)    recv(sock) <--- send(sock,,)    二回目以降        ループ始め      send(sock) ---> recv(sock,,)    recv(sock) <--- send(sock,,)          --->  |--- (制限時間 <---  (制限時間オーバー)---| |   オーバー通知)   :::        |   |         --->  | |    結果通知 <---   send(sock,,)(優勝) | |   ループ終わり ループ終わり      | ↓ ↓ 終了        終了   

4:プログラムの実現

<1>優勝の判断

サーバ側

int champion=3;

:::

winS++;

if(winS==champion){

(4)

remotelen);return 0;

}else if ((handC==0 &&handS==2)

||(handC==1 &&handS==0)

||(handC==2 &&handS==1)){

winC++;

if(winC==champion){

sendto(sock,"+You're the CHAMPION",20, 0,(const struct sockaddr *)

&remote, remotelen);return 0; }

}

クライアント側

if(recvbuf[0]=='+'||recvbuf[0]=='-')return 0;

/*******************************************************************

もしサーバが優勝したら、クライアントに”-You lost!Game over”というメッ

セージを送る、 メッセージの頭文字’ー’と’+’はクライアント側にゲーム結

果の符号である。

*******************************************************************/

<2>制限時間をオーバーした場合の処理

struct fd_set fds,readfds;

int n;

struct timeval tv;

:::

while(1){

:::

FD_ZERO(&readfds);

FD_SET(sock,&readfds);

tv.tv_sec=10;

tv.tv_usec=0;

memcpy(&fds,&readfds,sizeof(fd_set));

n=select(sock+1,&fds,NULL,NULL,&tv);

if(n==0){

sendto(sock,"-Time over!!",20, 0,(const struct sockaddr *) &remote,

remotelen);

printf("time over\n");

return 0; }

:::

}

(5)

5:テスト

<1>テスト項目

---1:ゲームに参加/不参加の返事に対するサーバ側の処理

ー→y/n を入力された場合と他のアルファベットを入力された場合に対する

サーバ側の処理を確認する。

---2:制限時間をオーバーした場合に対するサーバ側の処理

ー→クライアントは制限時間内に返事しない時に、サーバが正しく止まるか

を確認する。

---3:制限時間オーバーによりサーバが止まった後、クライアントは送信した

場合に対するクライアント側の処理

ー→サーバからの終了メッセージを正しく受信したか、クライアントが正し

く処理したかを確認する。

---4:優勝に対する処理

ー→優勝の条件を満たした場合に対する処理を確認する。

---5:クライアントからの手に対する処理

ー→クライアントから r/p/s または q を受けた場合とそれら以外の場合の処理。

テスト結果

---1:ゲームに参加/不参加の返事に対するサーバ側の処理結果

クライアントの入力

サーバの応答 テスト結果 y/n Input r/p/s or q.    w Erro,input y / n!

---2:制限時間をオーバーした場合に対するサーバ側の処理

 制限時間を過ぎると、サーバが time over を出力し、止まった。しかし、こ

の時点で、クライアントに終了メッセージを正しく送ったかは確認できない。

3確認結果に移る。

---3:制限時間オーバーによりサーバが止まった後、クライアントは送信した

場合に対するクライアント側の処理

 サーバが止まった後、クライアントは送信し、送信前に受け取ったサーバ

の終了メッセージ”-Time over!!”を表示し、クライアントプログラムが終了し

たことを確認した。

(6)

---4:優勝に対する処理

サーバ クライアント テスト結果 サーバが優勝した 止まった サーバから受信

-You lost!Game over

クライアントが優勝 した

止まった サーバから受信

+You're the CHAMPION

---5:クライアントからの手に対する処理

クライアントの手 サーバの応答 テスト結果 r/p/s 正しく判断 q ”-Game over”を送信した後、止まった w Erro,input again!

6:考察と感想

 サーバとクライアントとのデータの送受信については、どうも二回連続送

受信ができない(と思っている)、送信した後は受信を待ちである。また、

送信するデータの長さが長くなると、一部しか送信(受信)できない。この

点については、自分が間違っていると思っているが、サーバからの sock に

データの長さを書いても、クライアント側が一部しか表示できなかった。ど

こが門題になるのがどうしても見つからず、結局やり方を変えて、簡潔な

メッセージを送受信することにした。

7:参考文献

●UDP を聞ってみよう (2) 

URL

ーー http://x68000.q-e-d.net/~68user/net/udp-2.html

●select を聞う(タイムアウト付き)

URL

ーー http://www.geekpage.jp/programming/winsock/select-with-timeout.php

(7)

●クライアントプログラム #include <stdio.h>

#include <sys/socket.h> #include <netinet/in.h>

#include <sys/socket.h> // inet_addr #include <netinet/in.h> // inet_addr #include <arpa/inet.h> // inet_addr #include <string.h> // strncpy int main(){

struct sockaddr_in remote; char sendbuf[10], recvbuf[20]; int sock, ret;

sock = socket(PF_INET,SOCK_DGRAM,0); remote.sin_family = AF_INET; remote.sin_port = htons(60000); remote.sin_addr.s_addr = inet_addr("127.0.0.1"); strncpy(sendbuf,"1",1); while(1){ ret = sendto(sock, sendbuf,6,

0, (const struct sockaddr *) &remote, sizeof(remote)); ret = recvfrom(sock, recvbuf, sizeof(recvbuf)+20, 0, NULL, NULL); if (ret < 0) return -1; recvbuf[ret] = '\0'; printf("%s\n", recvbuf); if(recvbuf[0]=='+'||recvbuf[0]=='-')return 0; fgets(sendbuf,sizeof(sendbuf),stdin); } return 0; }

(8)

●サーバプログラム #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <stdlib.h> #include <string.h> int main(){

struct sockaddr_in local, remote;

char recvbuf[1500],join[1024]="Join the game?(y/n)"; int sock,champion=3,winC=0,winS=0;

socklen_t remotelen = sizeof(remote); sock = socket(PF_INET,SOCK_DGRAM,0); local.sin_family = AF_INET; local.sin_port = htons(60000); local.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sock,

(struct sockaddr *) &local, sizeof(local)) < 0)

{printf("error\n"); return -1;}

recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *) &remote,

&remotelen); // remotelen

sendto(sock,join,strlen(join)+1, 0,

(const struct sockaddr *) &remote, remotelen); while(1){

//返事待ち

recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *) &remote,

&remotelen); // remotelen if(recvbuf[0]=='n')break;

else if(recvbuf[0]=='y'){

sendto(sock,"Input r/p/s or q.",20, 0,(const struct sockaddr *) &remote, remotelen); while(1){

int handC,handS=(int) (3.0*random()/(RAND_MAX+1.0));//サーバの手 recvfrom(sock, recvbuf, sizeof(recvbuf), 0,

(9)

(struct sockaddr *) &remote, &remotelen); // remotelen //クライアントの手の決定 if (recvbuf[0] == 'q') break;

else if (recvbuf[0] == 'r') handC = 0; else if (recvbuf[0] == 'p') handC = 1; else if (recvbuf[0] == 's') handC = 2; else {

sendto(sock,"Erro,input again!",20,0,

(const struct sockaddr *) &remote, remotelen); continue;} if((handC==0 &&handS==1) ||(handC==1 &&handS==2) ||(handC==2 &&handS==0)){ winS++; if(winS==champion){

sendto(sock,"-You lost!Game over",20, 0,(const struct sockaddr *) &remote, remotelen);return 0;

}

sendto(sock,"You lost!Try again",20, 0,(const struct sockaddr *) &remote, remotelen); }

else if ((handC==0 &&handS==2) ||(handC==1 &&handS==0) ||(handC==2 &&handS==1)){ winC++;

if(winC==champion){

sendto(sock,"+You're the CHAMPION",20, 0,(const struct sockaddr *) &remote, remotelen);return 0;

}

sendto(sock,"You won!Next game",20, 0,(const struct sockaddr *) &remote, remotelen); }else if((handC==1&&handS==1)

||(handC==2&&handS==2) ||(handC==0&&handS==0)){

sendto(sock,"Same,input again",20, 0,(const struct sockaddr *) &remote, remotelen); }// y/n以外の文字を入力された場合

}

}else sendto(sock,"Erro,input y / n!",20,0,

(const struct sockaddr *) &remote, remotelen); }

return 0; }

参照

関連したドキュメント

理工学部・情報理工学部・生命科学部・薬学部 AO 英語基準入学試験【4 月入学】 国際関係学部・グローバル教養学部・情報理工学部 AO

例1) 自社又は顧客サーバの増加 例2) 情報通信用途の面積増加. 例3)

・「SBT (科学と整合した目標) 」参加企業 が所有する制度対象事業所の 割合:約1割. ・「TCFD

<RE100 ※1 に参加する建設・不動産業 ※2 の事業者>.

3 学位の授与に関する事項 4 教育及び研究に関する事項 5 学部学科課程に関する事項 6 学生の入学及び卒業に関する事項 7

赤坂 直紀 さん 石井 友理 さん.

 活動回数は毎年増加傾向にあるが,今年度も同じ大学 の他の学科からの依頼が増え,同じ大学に 2 回, 3 回と 通うことが多くなっている (表 1 ・図 1

「学部・学年を超えた参加型ディスカッションアクティビティ」の事例として、With café