いろんなものはつながっている

ネットワークプログラミング基礎 UDPホールパンチング

当初の目標であったUDPホールパンチングの模倣をしてみた。だらだらとかいただけでエラー処理とかなにもしてないが、
①二人のユーザがサーバにアクセスし、
②サーバは各ユーザの相手方のIP、ポート番号をユーザに送信し、
③各ユーザはサーバから受け取った情報をもとに相手方に送信する
ことを実装してみた。
UDP1

// UDPホールパンチング サーバ

#include "stdafx.h"

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

#include <winsock2.h>
#include <ws2tcpip.h>

#define PORT 9876	// 使用するポート番号

#define BUFFER_SIZE 1025

typedef struct ADDRESS_INFO_{
	bool bIsAddress;
	TCHAR szIP[16];
	TCHAR szPort[8];
} ADDRESS_INFO;

ADDRESS_INFO AddressArray[2];

void SetAddress(SOCKADDR_IN* Addr);
bool GetAddress(SOCKADDR_IN* Addr, TCHAR* szIP, TCHAR* szPort);

int _tmain(int argc, _TCHAR* argv[])
{
	// WinSockの初期化
	WSADATA data;
	WSAStartup(MAKEWORD(2,0), &data);

	// ソケットをデータグラムで開く
	int nServerSocket = socket(AF_INET, SOCK_DGRAM, 0);

	// ソケットにIPとポートを割り当てる
	SOCKADDR_IN addrin;
	memset(&addrin, 0, sizeof(addrin));
	addrin.sin_port = htons(PORT);
	addrin.sin_family = AF_INET;
	addrin.sin_addr.s_addr = htonl(INADDR_ANY);
	int nRt = bind(nServerSocket, (LPSOCKADDR)&addrin, (int)sizeof(addrin));

	// クライアントからの接続をまつ
	TCHAR szBuf[BUFFER_SIZE];
	SOCKADDR_IN addrfrom;
	while(1){
		int nSizeAddrFrom = sizeof(addrfrom);
		nRt = recvfrom(nServerSocket, szBuf, (int)sizeof(szBuf) - 1, 0, (SOCKADDR*)&addrfrom, &nSizeAddrFrom);
		_tprintf(_T("%sから接続をうけました。\n"), inet_ntoa(addrfrom.sin_addr));
		szBuf[nRt] = _T('\0');
		SetAddress(&addrfrom);

		// 接続元に相手のIP,Port番号を送信
		TCHAR szPairIP[16], szPairPort[8]; 
		bool bIsPair = GetAddress(&addrfrom, szPairIP, szPairPort);
		TCHAR szMessage[64];
		memset(szMessage, _T('\0'), sizeof(szMessage));
		if(bIsPair){
			_tcscpy(szMessage, _T("UDPHOLE"));
			_tcscat(szMessage, _T(":"));
			_tcscat(szMessage, szPairIP);
			_tcscat(szMessage, _T(":"));
			_tcscat(szMessage, szPairPort);
			int nSizeAddrFrom = sizeof(addrfrom);
			_tprintf(_T("%s:%dに相手のIP=%s、Port=%sを送信\n"), 
				inet_ntoa(addrfrom.sin_addr), addrfrom.sin_port, szPairIP, szPairPort);
		} else {
			_tcscpy(szMessage, _T("Dummy"));
		}
		sendto(nServerSocket, szMessage, (int)_tcslen(szMessage), 0, (SOCKADDR*)&addrfrom, nSizeAddrFrom);
		_tprintf(_T("%s:%dに%sを送信\n"), inet_ntoa(addrfrom.sin_addr), addrfrom.sin_port, szMessage);
	}

	closesocket(nServerSocket);
	WSACleanup();

	return 0;
}


void SetAddress(SOCKADDR_IN* pAddr)
{
	for(int i = 0; i < 2; i++){
		if(AddressArray[i].bIsAddress == true){	// すでに登録済み
			if(	(_tcscmp(AddressArray[i].szIP,  inet_ntoa(pAddr->sin_addr)) == 0) &&
				(_tstoi(AddressArray[i].szPort) == ntohs(pAddr->sin_port))){
				break;
			}
		}
		if(AddressArray[i].bIsAddress == false){ // 登録する
			AddressArray[i].bIsAddress = true;
			_tcscpy(AddressArray[i].szIP, inet_ntoa(pAddr->sin_addr));
			_stprintf(AddressArray[i].szPort, _T("%d"), ntohs(pAddr->sin_port));
			break;
		}
	}
}

bool GetAddress(SOCKADDR_IN* pAddr, TCHAR* szIP, TCHAR* szPort)
{
	int i = 0;
	for(; i < 2; i++){
		if(AddressArray[i].bIsAddress == true){
			if(	(_tcscmp(AddressArray[i].szIP,  inet_ntoa(pAddr->sin_addr)) != 0) ||
				(_tstoi(AddressArray[i].szPort) != ntohs(pAddr->sin_port))){
				_tcscpy(szIP, AddressArray[i].szIP);
				_tcscpy(szPort, AddressArray[i].szPort);
				break;
			}
		}
	}

	if(i < 2) {
		return true;
	} else {
		return false;
	}
}
// UDPホールパンチング クライアント

#include "stdafx.h"

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

#include <winsock2.h>
#include <ws2tcpip.h>

#define SERVER_PORT 9876	// サーバのポート番号

#define BUFFER_SIZE 1024

void SetPairAddress(TCHAR* szbuf, TCHAR* szIP, int& nPort);

int _tmain(int argc, _TCHAR* argv[])
{
	// WinSockの初期化
	WSADATA data;
	WSAStartup(MAKEWORD(2,0), &data);

	// ソケットの生成(TCP用)
	int nClientSocket = socket(AF_INET, SOCK_DGRAM, 0);	

	// IP,ポート番号の設定
	struct sockaddr_in ServerAddr;
	memset(&ServerAddr, 0, sizeof(ServerAddr));
	ServerAddr.sin_port = htons(SERVER_PORT);
	ServerAddr.sin_family = AF_INET;
	ServerAddr.sin_addr.s_addr = inet_addr(_T("192.168.11.6"));

	// サーバにメッセージを送り相手の情報をうけとる。
	SOCKADDR_IN FromAddr;
	TCHAR szBuffer[BUFFER_SIZE];
	memset(szBuffer, _T('\0'), sizeof(szBuffer));
	while(1){
		TCHAR szDummy[] = _T("test");
		int nRtn = sendto(nClientSocket, szDummy, (int)_tcslen(szDummy), 0, 
			(LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));
		int nSizeFromAddr = sizeof(FromAddr);
		nRtn = recvfrom(nClientSocket, szBuffer, (int)sizeof(szBuffer), 
			0, (SOCKADDR*)&FromAddr, &nSizeFromAddr);
		if(_tcsstr(szBuffer, _T("UDPHOLE")) != NULL){
			break;
		}
	}

	// 相手のIPとPortを設定
	TCHAR szPairIP[16];
	int nPairPort;
	SetPairAddress(szBuffer, szPairIP, nPairPort);
	SOCKADDR_IN PairAddr;
	memset(&PairAddr, 0, sizeof(PairAddr));
	PairAddr.sin_port = htons(nPairPort);
	PairAddr.sin_family = AF_INET;
	PairAddr.sin_addr.s_addr = inet_addr(szPairIP);

	// 相手にメッセージを送る
	while(1){
		memset(szBuffer, _T('\0'), sizeof(szBuffer));
		_tcscpy(szBuffer, _T("Oooi"));
		_tprintf(_T("%s:%dにメッセージを送る:%s\n"), 
			inet_ntoa(PairAddr.sin_addr), PairAddr.sin_port, szBuffer);
		int nRtn = sendto(nClientSocket, szBuffer, (int)_tcslen(szBuffer),
					0, (LPSOCKADDR)&PairAddr, sizeof(PairAddr));
		int nSizeFromAddr = sizeof(FromAddr);
		TCHAR szRecvBuffer[BUFFER_SIZE];
		memset(szRecvBuffer, _T('\0'), sizeof(szRecvBuffer));
		nRtn = recvfrom(nClientSocket, szRecvBuffer, (int)sizeof(szRecvBuffer), 
					0, (SOCKADDR*)&FromAddr, &nSizeFromAddr);
		_tprintf(_T("%s:%dからメッセージ:%s サイズ:%d\n"), 
			inet_ntoa(FromAddr.sin_addr), FromAddr.sin_port, szBuffer, nRtn);
	}

	closesocket(nClientSocket);
	WSACleanup();

	return 0;

}

void SetPairAddress(TCHAR* szBuf, TCHAR* szIP, int& nPort)
{
	TCHAR* pCh = _tcstok(szBuf, _T(":"));
	// IPを抽出
	pCh = _tcstok(NULL, _T(":"));
	_tcscpy(szIP, pCh);
	// Portを抽出
	TCHAR szPort[16];
	pCh = _tcstok(NULL, _T(":"));
	_tcscpy(szPort, pCh);
	nPort = _tstoi(szPort);       
}

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

スポンサード リンク

カテゴリー

スポンサード リンク