UDP通信について
前回のことでかなり言われたので改変版を見てもらいたいと思います。
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);
}
となっております。
補足
ありがとうございます. getsockname()の場合connect()が必要なので, UDPの場合は一般的でないですね。