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

ネットワークプログラミング基礎 UDP接続

winsocketを用いてUDP接続をしてみる。UDP接続のおおまかな流れは以下。
UDP1_1

// UDP接続(同期型)プログラム サーバ側

#include "stdafx.h"

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

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

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

#define BUFFER_SIZE 1024

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);
		szBuf[nRt] = _T('\0');
		_tprintf(_T("%s"), szBuf);
		if(_tcscmp(szBuf, _T("c_end")) == 0){
			break;
		}
	}

	closesocket(nServerSocket);
	WSACleanup();

	return 0;
}
// UDP接続(同期型)プログラム クライアント側

#include "stdafx.h"

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

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

#define PORT 9876

#define BUFFER_SIZE 1024

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

	// ソケットをデータグラムで開く
	int nClientSocket = socket(AF_INET, SOCK_DGRAM, 0);
	
	// 送信先のIP,Portを設定
	SOCKADDR_IN addrin;
	memset(&addrin, 0, sizeof(addrin));
	addrin.sin_port = htons(PORT);
	addrin.sin_family = AF_INET;
	addrin.sin_addr.s_addr = inet_addr("192.168.11.6");

	TCHAR szBuffer[BUFFER_SIZE];
	memset(szBuffer, _T('\0'), sizeof(szBuffer));
	// メッセージを送る
	while(1){
		_tprintf(_T("入力してください"));
		gets(szBuffer);
		int nRtn = sendto(nClientSocket, szBuffer, (int)_tcslen(szBuffer),
					0, (LPSOCKADDR)&addrin, sizeof(addrin));
		if(nRtn != (int)_tcslen(szBuffer)){
			_tprintf(_T("送信エラー"));
		}
	}

	closesocket(nClientSocket);
	WSACleanup();

	return 0;
}

猫でわかるネットワークプログラミングにUDPを用いた例としてNTPサーバから時刻を受信する例がのっていた。それを参考に作成したエラー処理を含めていないコードが以下。

// SNTPサーバから時刻を取得する
//
#include "stdafx.h"

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

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

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

#define NTP_PORT 123

#define BUFFER_SIZE 1024

// SNTPのパケット
typedef struct Packet_ {
	int nControlWord;
	int nRootDelay;
	int nReferenceIdentifier;
	__int64 nReferenceTimestamp;
	__int64 nOriginateTimestamp;
	__int64 nReceiveTimestamp;
	int nTransmitTimestampsecond;
	int nTransmitTimestampfraction;
} SNTP_PACKET;

int _tmain(int argc, _TCHAR* argv[])
{

	// WinSockの初期化
	WSADATA data;
	int nRtn = WSAStartup(MAKEWORD(2,0), &data);

	// ソケットの作成
	int nSocket = socket(AF_INET, SOCK_DGRAM, 0);

	// 受信用にソケットにIP,Portを設定
	SOCKADDR_IN ClientAddr;
	memset(&ClientAddr, 0, sizeof(ClientAddr));
	ClientAddr.sin_family = AF_INET;
	ClientAddr.sin_port = htons(CLIENT_PORT);
	ClientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	nRtn = bind(nSocket, (SOCKADDR*)&ClientAddr, sizeof(ClientAddr));

	// NTPサーバ情報を設定
	TCHAR szNTPServerName[] = _T("ntp.tut.ac.jp");
	HOSTENT* lpHostent = gethostbyname(szNTPServerName);
	if(lpHostent == NULL) return -1;

	// NTPサーバへの問い合わせ
	SNTP_PACKET SNTPPacket;
	memset(&SNTPPacket, 0, sizeof(SNTPPacket));
	SNTPPacket.nControlWord = htonl(0x0B000000);

	SOCKADDR_IN ServerAddr;
	memset(&ServerAddr, 0, sizeof(ServerAddr));
	ServerAddr.sin_family = AF_INET;
	ServerAddr.sin_port = htons(NTP_PORT);
	ServerAddr.sin_addr.s_addr = *((unsigned long*)lpHostent->h_addr);

	nRtn = sendto(nSocket, (const char*)&SNTPPacket, sizeof(SNTPPacket), 0,
				(SOCKADDR*)&ServerAddr, sizeof(ServerAddr));

	// NTPサーバからのレスポンスを受け取る
	int nSizeOfAddr = sizeof(SOCKADDR_IN);
	nRtn = recvfrom(nSocket, (char*)&SNTPPacket, sizeof(SNTP_PACKET), 0,
				(SOCKADDR*)&ServerAddr, &nSizeOfAddr);

	time_t ServerTime = ntohl(SNTPPacket.nTransmitTimestampsecond) - 2208988800;
	struct tm* lpgtime = gmtime(&ServerTime);

	SYSTEMTIME st;
	st.wYear = lpgtime->tm_year + 1900;
	st.wMonth = lpgtime->tm_mon + 1;
	st.wDay = lpgtime->tm_mday;
	st.wHour = lpgtime->tm_hour;
	st.wMinute = lpgtime->tm_min;
	st.wSecond = lpgtime->tm_sec;
	st.wMilliseconds = 0;
	
	SetSystemTime(&st);

	_tprintf(_T("システム時間をサーバ時間にあわせました\n"));
	_tprintf(_T("%d年%d月%d日%d時%d分%d秒"), st.wYear, st.wMonth, st.wDay, 
		st.wHour + 9, st.wMinute, st.wSecond); 

	return 0;
}

送信したパケットをパケットキャプチャでみると、サーバから時間を教えてもらうためにクライアントから送ったパケットはVersion = 1, Leap = 0, Mode = 3となっていることが確認できる。
UDP1_2
受信した情報には時刻が含まれていることが確認できる。
UDP1_3

関連記事

コメント

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

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

スポンサード リンク

カテゴリー

スポンサード リンク