dポイントプレゼントキャンペーン実施中!

前回のことでかなり言われたので改変版を見てもらいたいと思います。
TCPと伝えていましたが今回、UDPに変えました。
ヘッダーはこのようになっております。

==wsock.h==

#include <Windows.h>
#include <stdio.h>

#pragma comment(lib,"WSock32.lib")

#define PORT_NO 8000ポート番号
#define SERVER_NAME ""

enum MINE{
NONE,
SERVER,
CLIENT
};

ソケット通信
class WSOCK{
private:
WSADATA wsaData;
SOCKET s;
SOCKADDR_IN saddr;
int rtn;
int state;
MINE mineFlg;
char szStr[256];エラーメッセージ用
u_short port;変換後のポート番号
int fromlen;受信したサイズ
HOSTENT *lpHost;ホスト情報
ファイルディスクプリタをまとめた構造体
//→ソケット判別する為の管理情報
fd_set fds,readfds;

public:
char szRcvBuf[1024];受信バッファ
char szSndBuf[1024];送信バッファ
SOCKADDR_IN from;ソケットアドレス構造体
WSOCK();
~WSOCK();
bool ServerRcv();受信
bool ServerSnd();送信
bool CliantRcv();受信
bool CliantSnd();送信
void SarverSet();
void ClientSet();
bool EnumMyIPAddress();
};
==wsock.cpp==
#include "wsock.h"
コンストラクタ
WSOCK::WSOCK(){
//WinSock初期化
rtn = WSAStartup(MAKEWORD(2,2),&wsaData);
if(rtn != 0){
MessageBox(NULL,"WSAStartup失敗",
"ERROR",MB_OK);
state = -1;
}
ソケットを開く
s = socket(AF_INET,SOCK_DGRAM,0);
if(s<0){
MessageBox(NULL,"ソケットをオープンできません",
"eRROR",MB_OK);
WSACleanup();
state = 2;
}
0で初期化
memset(&saddr,0,sizeof(SOCKADDR_IN));
saddr.sin_family = AF_INET;//アドレスファミリー
saddr.sin_port = htons(PORT_NO);//ポート
mineFlg = SERVER;
サーバ側設定
if(mineFlg == SERVER)
{
SarverSet();
}
if(mineFlg == CLIENT)
{クライアント
ClientSet();
}
}
WSOCK::~WSOCK(){
closesocket(s);

ソケットのリソース解放
rtn = WSACleanup();
if(rtn == SOCKET_ERROR){
MessageBox(NULL,"WSACleanup失敗","ERrOR",MB_OK);
state = -2;
}
}
//受信
bool WSOCK::ServerRcv(){
読み込み用fd_setの初期化
selectが毎回内容を上書きしてしまうので毎回初期化
memcpy(&fds,&readfds,sizeof(fd_set));

struct timeval timeout = {0,0};  //{1秒以上の部分()s、1秒以下の部分(ms)}

fdsに設定されたソケットが読み込み可能になるまで待つ
select(0,&fds,NULL,NULL,&timeout);

ソケット読み込み可能データがある場合
if(FD_ISSET(s,&fds)){
fromlen = (int)sizeof(from);
//nullで初期化
memset(szRcvBuf,'\0',sizeof(szRcvBuf));
//受信処理
rtn = recvfrom(s,szRcvBuf,(int)sizeof(szRcvBuf)-1,0,
(SOCKADDR*)&from,&fromlen);
if(rtn == SOCKET_ERROR){
MessageBox(NULL,"recvfromエラー","ERRoR",MB_OK);
return false;
}
}
szRcvBuf[rtn] | '\0';//NULLコード
if(strcmp(szRcvBuf,"c_end") == 0){
MessageBox(NULL,"クライアントが接続を切りました","ERROr",MB_OK);
return false;
}
return true;
}
送信
bool WSOCK::ServerSnd(){
char buf[1024];
memset(buf,0,sizeof(buf));
//_snprintf:書式指定文字付きデータ書き込み
_snprintf(buf,sizeof(buf),"data to port 8000");
//送信処理
rtn = sendto(s,szSndBuf,(int)strlen(szSndBuf)+1,
0,(LPSOCKADDR)&from,送り先サーバ/クライアント
sizeof(from));サイズ
if(rtn != (int)strlen(szSndBuf)+1){
MessageBox(NULL,"sendtoエラー","サーバーエラ",MB_OK);
closesocket(s);
WSACleanup();
return false;
}
return true;
}

受信
bool WSOCK::CliantRcv(){
fromlen = (int)sizeof(from);
//nullで初期化
memset(szRcvBuf,'\0',sizeof(szRcvBuf));
//受信処理
rtn = recvfrom(s,szRcvBuf,(int)sizeof(szRcvBuf)-1,0,
(SOCKADDR*)&from,&fromlen);
if(rtn == SOCKET_ERROR){
MessageBox(NULL,"recvfromエラー","ERRoR",MB_OK);
return false;
}
szRcvBuf[rtn] | '\0';//NULLコード
if(strcmp(szRcvBuf,"s_end") == 0){
MessageBox(NULL,"接続を切りました","ERROr",MB_OK);
return false;
}
return true;
}

送信
bool WSOCK::CliantSnd(){
送信処理
rtn = sendto(s,szSndBuf,(int)strlen(szSndBuf)+1,
0,(LPSOCKADDR)&saddr,送り先サーバ/クライアント
sizeof(saddr));サイズ
if(rtn != (int)strlen(szSndBuf)+1){
MessageBox(NULL,"sendtoエラー","erROR",MB_OK);
closesocket(s);
WSACleanup();
return false;
}
return true;
}
void WSOCK::SarverSet(){
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
ソケットにローカルアドレスを関連付ける
if(bind(s,(LPSOCKADDR)&saddr,
(int)sizeof(saddr)) == SOCKET_ERROR){
MessageBox(NULL,"bindエラー","er",MB_OK);
closesocket(s);
WSACleanup();
state = -3;
}
FD_ZERO(&readfds);
FD_SET(s,&readfds);
}
void WSOCK::ClientSet(){
   クライアント側設定
   ホスト名からホスト情報を取得
lpHost = gethostbyname(SERVER_NAME);
サーバのアドレスをセット
memcpy(&(saddr.sin_addr),
lpHost->h_addr_list[0],//サーバのアドレス
lpHost->h_length);
}

となっております。

A 回答 (3件)

UDPの場合はルータ越えの問題もあるからブロードバンド・ルータを間に挟むならポート開放が必須です。

このポート開放がクライアント側にも発生するという非常に初心者向きじゃないので避けたほうが良いと思います。
    • good
    • 0

なぜTCPではなくUDPを選択したのでしょう?



単にTCPを使ってみたけどうまく通信できなかったから、とか、TCPではデータが意図せず分割されたり統合されたりして受信側の処理が面倒になるから、などという理由でTCPを使わずUDPを選んだのだとしたら絶対にやめておくべきです。

UDPは信頼性の低いプロトコルと言われるだけあって、

・パケットの順序が保証されない。送信側で「AAA」「BBB」「CCC」の順に送信したのに、受信側には「CCC」「AAA」「BBB」の順に届くかもしれない。

・パケットが破棄されるかもしれない。送信側で「AAA」「BBB」「CCC」と送信したのに、受信側には「AAA」「CCC」だけ届くかもしれない。

・1つのパケット送信に対して1回だけ受信するとは限らない。送信側で「AAA」「BBB」と送信したら、受信側では「AAA」「AAA」「BBB」と届くかもしれない。

などなどの様々な問題をクリアしていかなければいけないのですが。
もし、あなたがこれらの課題を自分のプログラムの中で解決できるか、作ろうとしているプログラムでは通信でこれらの現象が発生しても問題ないというのであれば、UDPを使い続けても問題ないでしょう。もしそうでなければ、TCPに戻すべきだと思います。

UDPを使うのは以下のような場合でしょうか…。

・TCPじゃ間に合わないくらいのリアルタイム性が要求される場合
・データがある程度失われてもどうにかなる場合
・通信データ量が小さく、上記問題も簡単に解決できるか、そもそも考慮する必要がない場合
    • good
    • 0

別アカウントですが同じ質問者です。


通信している場所はこちらになります。
やりたいことはボードゲームの通信です。
ずっと通信をしてなにかアクションがあればアクションがあったchar型をもたせて受信側に送り、ターンチェンジする方法を行いたいと思っております。
その方法がわかりません。
すみませんがアドバイスよろしくお願いします(>人<;)

//受信
switch(mineFlg)
{
case NONE:
break;

case SERVER:

//受信
ServerRcv();
if(lstrlen(szRcvBuf) > 0)
{
if(strncmp(szRcvBuf,"NULL",3) == 0)
{
char strEx[4];
memset(strEx,'\0',sizeof(strEx));
flg = true;
}
}
if(flg){
//送信情報の作成
memset(szSndBuf,'\0',sizeof(szSndBuf));
wsprintf(szSndBuf,"NULL");

//送信処理
ServerSnd();
}

break;

case CLIENT:

//送信情報の作成
memset(szSndBuf,'\0',sizeof(szSndBuf));
wsprintf(szSndBuf,"NULL");

//送信処理
CliantSnd();

//受信
CliantRcv();
if(lstrlen(szRcvBuf) > 0){
if(strncmp(szRcvBuf,"NULL",3) == 0){
char strEx[4];
memset(strEx,'\0',sizeof(strEx));
}

if(strncmp(szRcvBuf,"clear",3) == 0){
char strEx[4];
memset(strEx,'\0',sizeof(strEx));
for(int i=0;i<PIECE_RANGE;i++){
memcpy(strEx,&szRcvBuf[3],3);
Piece_Black[i].vecPos.x = atoi(strEx);
memcpy(strEx,&szRcvBuf[6],3);
Piece_Black[i].vecPos.z = atoi(strEx);
}
}
}


break;
}
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!