UDPのネット通信

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
COUTION

UDPのネット通信

#1

投稿記事 by COUTION » 15年前

結構(?)前に質問させてもらったCOUTIONです
使用言語はVC++2010、DXライブラリです

UDP通信でなんとか4人までの座標の位置を表示させることはできたんですが、
接続するのに使用するポートを全員開放してないと通信プレイできません。

他のネット対戦できるゲームなどを見るとホスト(サーバー)だけポート開放すれば
ネット対戦できますよね?

どうしたら出来るんでしょうか?
それともUDPじゃ出来ないんでしょうか?

それともし好ければ通信プレイのよく使われるソースの書き方や仕組みなど教えてくださいw

一応ソースを載せておきます
アドバイスなどあればお願いします!
void NetSocketSend(){
    // UDP通信用のソケットハンドルを作成
    NetUDPHandle = MakeUDPSocket( 10800 ) ;
    // IPアドレスを設定( ここにある4つのIP値は仮です )
    Ip.d1 = 000 ;
    Ip.d2 = 000 ;
    Ip.d3 = 000 ;
    Ip.d4 = 000 ;
}

void setuzokuOK(){
    char setuzoku[/url]="000";
    NetWorkSendUDP( NetUDPHandle, Ip, 10800, setuzoku , 4 ) ;
    // 文字列の受信を待つ
    while( CheckNetWorkRecvUDP( NetUDPHandle ) == FALSE )
    {
        // ウインドウズメッセージ処理
        if( ProcessMessage() < 0 ){
            mode=999 ;
            break;
        }
    }
    NetWorkRecvUDP( NetUDPHandle, NULL, NULL, StrBuf, 4, NULL ) ;
    if(strncmp(StrBuf, "000", 3)==0){
        Netmode+=10;
    }else mode=999;
}

void NetSocketRecvHost(){
    NetUDPHandle = MakeUDPSocket( 10800 ) ;
    Netmode+=10;
}

void NetmodeSend(){
        char chxp[/url]="9990000";
    char chyp[/url]="9990000";
        sprintf(chxp,"001%04d",ch.x);
    sprintf(chyp,"002%04d",ch.y);
    NetWorkSendUDP( NetUDPHandle, Ip, 10800, chxp , 8 ) ;
    NetWorkSendUDP( NetUDPHandle, Ip, 10800, chyp , 8 ) ;
}

void NetmodeSendHost(){
    char chxp[/url]="9990000";
    char chyp[/url]="9990000";
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            if(Ipflag==1){
                if(i==j){
                    sprintf(chxp,"%d01%04d",i,ch.x);
                    sprintf(chyp,"%d02%04d",i,ch.y);
                }else{
                    sprintf(chxp,"%d01%04d",i,chNetx);
                    sprintf(chyp,"%d02%04d",i,chNety);
                }
                NetWorkSendUDP( NetUDPHandle, IpS[j], 10800, chxp , 8 ) ;
                NetWorkSendUDP( NetUDPHandle, IpS[j], 10800, chyp , 8 ) ;
            }
        }
    }
}

void NetmodeRecvHost(){
    char StrBuf2[ 256 ] ;    // データバッファ
    int i,j,k;
    while(CheckNetWorkRecvUDP( NetUDPHandle ) == TRUE){
        NetWorkRecvUDP( NetUDPHandle, &Ips, NULL, StrBuf, 8, NULL) ;
        if(strncmp(StrBuf, "000", 3)==0){
            for(i=0;i<3;i++){
                if(Ipflag==0){
                    NetWorkSendUDP( NetUDPHandle, Ips, 10800, "000" , 4 ) ;
                    Ipflag=1;
                    IpS.d1 = Ips.d1 ;
                    IpS.d2 = Ips.d2 ;
                    IpS.d3 = Ips.d3 ;
                    IpS.d4 = Ips.d4 ;
                    i=3;
                }
            }
        }
        for(i=0;i<3;i++){
            if(Ipflag==1){
                if(IpS[i].d1 == Ips.d1&&IpS[i].d2 == Ips.d2&&IpS[i].d3 == Ips.d3&&IpS[i].d4 == Ips.d4){
                    if(strncmp(StrBuf, "001", 3)==0){
                        k = strlen(StrBuf);
                        for(j=3;j<k;j++){
                            StrBuf2[j-3] = StrBuf[j]; 
                        }
                        StrBuf2[j]='\0';
                        chNetx[i] = atoi(StrBuf2);
                    }
                    if(strncmp(StrBuf, "002", 3)==0){
                        k = strlen(StrBuf);
                        for(j=3;j<k;j++){
                            StrBuf2[j-3] = StrBuf[j]; 
                        }
                        StrBuf2[j]='\0';
                        chNety[i] = atoi(StrBuf2);
                    }
                }
            }
        }
    }
}

void NetmodeRecv(){
    char StrBuf2[ 256 ] ;    // データバッファ
    int i,j;
    while(CheckNetWorkRecvUDP( NetUDPHandle ) == TRUE){
        NetWorkRecvUDP( NetUDPHandle, NULL, NULL, StrBuf, 8, NULL) ;
        if(strncmp(StrBuf, "001", 3)==0){
            i = strlen(StrBuf);
            for(j=3;j<i;j++){
                StrBuf2[j-3] = StrBuf[j]; 
            }
            StrBuf2[j]='\0';
            chNetx[0] = atoi(StrBuf2);
        }
        if(strncmp(StrBuf, "002", 3)==0){
            i = strlen(StrBuf);
            for(j=3;j<i;j++){
                StrBuf2[j-3] = StrBuf[j]; 
            }
            StrBuf2[j]='\0';
            chNety[0] = atoi(StrBuf2);
        }
        if(strncmp(StrBuf, "101", 3)==0){
            i = strlen(StrBuf);
            for(j=3;j<i;j++){
                StrBuf2[j-3] = StrBuf[j]; 
            }
            StrBuf2[j]='\0';
            chNetx[1] = atoi(StrBuf2);
        }
        if(strncmp(StrBuf, "102", 3)==0){
            i = strlen(StrBuf);
            for(j=3;j<i;j++){
                StrBuf2[j-3] = StrBuf[j]; 
            }
            StrBuf2[j]='\0';
            chNety[1] = atoi(StrBuf2);
        }
        if(strncmp(StrBuf, "201", 3)==0){
            i = strlen(StrBuf);
            for(j=3;j<i;j++){
                StrBuf2[j-3] = StrBuf[j]; 
            }
            StrBuf2[j]='\0';
            chNetx[2] = atoi(StrBuf2);
        }
        if(strncmp(StrBuf, "202", 3)==0){
            i = strlen(StrBuf);
            for(j=3;j<i;j++){
                StrBuf2[j-3] = StrBuf[j]; 
            }
            StrBuf2[j]='\0';
            chNety[2] = atoi(StrBuf2);
        }
    }
}

void NetmodeMain(){
    if(Netmode==0){
        NetSocketSend();
        setuzokuOK();
    }else if(Netmode==1){
        NetSocketRecvHost();
    }
    if(Netmode==10){
        NetmodeSend();
        NetmodeRecv();
    }else if(Netmode==11){
        NetmodeSendHost();
        NetmodeRecvHost();
    }
}

softya

Re:UDPのネット通信

#2

投稿記事 by softya » 15年前

UDPなままだと無理だと思います。
ただし、UPnPを使えばソフト的にポート開放できますのでUDPでもポート開放の手間は無くせます。
http://hp.vector.co.jp/authors/VA011804/upnp.htm
知ったかぶりで書いてますがUPnPを使ったことがないので、トラブルには答えられないかもしれません。

あるいは、UDPに比べてリアルタイム性に欠けますがTCPならサーバ/クライアント型にすれば大丈夫です。
問題点というか設計の注意としてクライアントはサーバーに問いかけてサーバーの返却値として情報を受け取る形になりますので、サーバーは問いかけのない限りクライアントに情報を送る方法がありません。
4人で遊ぶすれば1台をサーバーにしてポート開放します。残り三人は、そのサーバーに接続してクライアントして動作します。これでもアクションゲーム類でない限りはTCPでも速度的には問題ないはずです。

COUTION

Re:UDPのネット通信

#3

投稿記事 by COUTION » 15年前

なるほどsoftyaさんありがとうございます
UPnPなら簡単に開放できそうですね

でもオンラインゲームみたいに誰でも何もせず参加出来る感じにしたいのですが
もろアクションゲームな感じで結構速度は必要だと思ってます

ゲーム起動するだけで自動的に開放させるとか出来ないんでしょうか?
オンラインゲームのFPSなどもTCPでやってるんでしょうか?

softya

Re:UDPのネット通信

#4

投稿記事 by softya » 15年前

>でもオンラインゲームみたいに誰でも何もせず参加出来る感じにしたいのですが
>もろアクションゲームな感じで結構速度は必要だと思ってます

>ゲーム起動するだけで自動的に開放させるとか出来ないんでしょうか?
>オンラインゲームのFPSなどもTCPでやってるんでしょうか?

メーカーの作っているものは、まずマッチング・コネクション用のサーバーがあります。
こことの接続はサイト閲覧等同様にTCPで接続できますからポート開放も不要です。
ロビーとか対戦相手を探していますって状態ですね。
個人で作るとしたら、レンタルサーバを借りてPHPとかで作るしか無いでしょう。

接続シーケンス
・各個人のクライアントはマッチング・サーバーに接続して対戦相手が揃うのを待ちます。定期的にクライアントはマッチングサーバと通信が必要です。
・対戦相手が揃ったら、それぞれのクライアントの接続ポートを決めます。
・各クライアントには接続に使う使うポートの情報を渡します。
・各クライアントはUPnPでポートを開放して、UDP接続しているのを待ちます。
って感じでどうしょうか。

COUTION

Re:UDPのネット通信

#5

投稿記事 by COUTION » 15年前

レンタルサーバーはちょっとお金がかかるので無理そうです

接続のシーケンスについてですが
すいません、ちょっと勘違いしてました
UPnPってのは各クライアント側が手動でやるのではなくて
各クライアント側がなにもせず自動で開放して通信プレイするってことですよね?

開放させるやり方が分からないので「NPnP C++」で検索してみたところ
ttp://loafer.jp/mixi/diary/class.xsp?2005-12-30-21-57
ttp://ohwhsmm7.blog28.fc2.com/blog-entry-15.html
などのサイトを見つけました
もちろんそのまま貼りつけただけじゃできずDXライブラリしか触れたことないので
よく書いてある意味もわかりません
このようなことをして開放するってことですか?

softya

Re:UDPのネット通信

#6

投稿記事 by softya » 15年前

そうです。
各クライアントがUPnPを使って自動でルータにポート開放を要求してルータにポートを開放させます。

>開放させるやり方が分からないので「NPnP C++」で検索してみたところ
>http://loafer.jp/mixi/diary/class.xsp?2005-12-30-21-57
>http://ohwhsmm7.blog28.fc2.com/blog-entry-15.html
>などのサイトを見つけました
>もちろんそのまま貼りつけただけじゃできずDXライブラリしか触れたことないので
>よく書いてある意味もわかりません
>このようなことをして開放するってことですか?

ルータと通信して解放処理を行ないます。
問題はルータが対応していないと手動解放しか手がないことですかね。

英語ですが、WindowsSDKにあるみたいです。
http://msdn.microsoft.com/en-us/library/aa382303.aspx
日本でのUPnPの解説は見つけられませんでしたが書籍はありました。
http://homepage3.nifty.com/ken_hamada/p ... index.html

COUTION

Re:UDPのネット通信

#7

投稿記事 by COUTION » 15年前

softyaさんいろいろ調べてくれてありがとうございます

自分でもいろいろ調べてみたんですが難しくてよく分からないです・・
英語も読めずで・・
とりあえずTCPでやってみようと思います!

COUTION

Re:UDPのネット通信

#8

投稿記事 by COUTION » 15年前

とりえずTCPでやってみたんですが、
結局お互いにポート開放してないとだめみたいです・・
DXライブラリだと無理なんでしょうか?

softya

Re:UDPのネット通信

#9

投稿記事 by softya » 15年前

>DXライブラリだと無理なんでしょうか?
DXライブラリだとやった事がないのですが、GetNewAcceptNetWork()のハンドルに対してNetWorkSend()とやってもだめでしょうか?[誤解を生みそうなので少し訂正]
どうしても相手にいきなりパケットを送りつけるにはポート開放が必要ですので受信したハンドルを使えば出来ないかと思いましたが。
ソースコードを貼ってもらったほうが良いかも知れません。

winsockなら次のような方法で出来るのですが。
下記はTCPサーバの例です。
http://www.geekpage.jp/programming/winsock/tcp.php

分からないことがあれば、聞いてください。 画像

COUTION

Re:UDPのネット通信

#10

投稿記事 by COUTION » 15年前

ありがとうございます
DXライブラリでクライアントはポート開放せず普通に接続できました
プログラムミスってました・・
やはり速度が多少遅くなったりしてますが、これで頑張ってみます!

閉鎖

“C言語何でも質問掲示板” へ戻る