WinSock / BSDSocket

【0限目】TCP/IP通信とは
[難易度:★☆☆☆☆] TCP/IP通信の基礎となる知識を習得します。


【1限目】Bit と Byte
[難易度:★★☆☆☆] コンピュータの最小単位、ビットとバイトについて学習します。


【2限目】ネットワークバイトオーダー
[難易度:★☆☆☆☆] ネットワーク上に流れるデータの規則について学習します。


【3限目】IPアドレス
[難易度:★★☆☆☆] IPアドレスについて学習します。(其の壱)


【4限目】グローバルIP と ローカルIP
[難易度:★★☆☆☆] IPアドレスについて学習します。(其の弐)


【5限目】fire wall と port
[難易度:★☆☆☆☆] ファイアウォールについて学習します。


【6限目】TCPの基礎理論 / 3 Way handshaking
[難易度:★☆☆☆☆] TCP通信はなぜ信頼性が高いのかについて学習します。

このエントリーをはてなブックマークに追加

もしあなたがオンラインゲームを作成する場合は注意が必要です。
1フレーム毎に1パケットを送ることはかなり難しいからです。

理由は単純で、1パケットを処理するのに掛かる時間は1フレームより長いからです。
なのでパケットは20フレームから30フレームに一度だけ送信するべきです。

え? それだと格闘ゲームが作れない?

そんな時は……仕方がないので1フレーム毎にパケットを送ります。その代わり、1パケットに5フレーム分位情報を持たせて下さいつまり1パケットに現在の挙動の前後の情報も持たせておくのです。
こうしておけば、パケットロスしても以前のパケットから相手の入力を読み取ることができます。

それか3フレーム単位で動く格闘ゲームを作って下さい。
このエントリーをはてなブックマークに追加

これまでのプログラムは全てTCPを用いて記述してきました。
復習になりますが、TCPの特徴としては、再送処理をTCPが行うことと、データサーキット(データの通信路のことです, SYN と SYN ACKのやり取りで構成します)を構成してからパケットを送信することでした。

それに対しUDPでは再送処理を行いません。データサーキットを構成することもありません。
送信の度に相手方のIPアドレスとポート番号を指定し、パケットを投げっぱなしにします。
TCPが糸電話なら、UDPは矢文です。
つまり、パケットがなんらかの電波障害によってロスすることもあります。

UDPのコードもTCPのコードとほとんど同じです。


8行目を見て下さい。
TCPでは、SYNを受け取る用のソケットと、実際のパケットを受け取るソケットは区別されていました。しかし、UDPではデータサーキットを構成しないので、SYNを受け取りません。
なのでacceptが必要ありません。よってソケットは1つあればよく、またブロッキングを起こしません。

19行目にて、プロトコルの種類を指定しています。UDPを使用するのでSOCK_DGRAMを使います。

最後に、22行目と23行目です。
recvfromrecvと同じ使い方をしますが、クライアントの情報を格納する引数が付きます。ただし、クライアントのことを知る必要がない場合は省略もできます。

recvfromの第一引数には、データをレシーブするソケットを指定します。
recvfromの第二引数には、読み込んだデータを格納するアドレスを指定します。
recvfromの第三引数には、読み込むサイズを指定します。
recvfromの第四引数には、基本的に0を指定します。読み出したデータをソケットバッファから削除しないか否かや、バンド外データを受信するか否かなどを指定することもできますが、あまり使いません。
recvfromの第五引数は、クライアントの情報を格納する構造体のアドレスを指定します。クライアントの情報が不要な場合はNULLを指定することもできます。
recvfromの第六引数は、第五引数のバイト単位の大きさを格納した変数のアドレスを指定します。
変数のアドレスしか受け取らないので仕方なく、22行目にて第六引数の大きさを計算しています。
第五引数にNULLを指定した場合、第六引数にもNULLを指定します。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
続いてクライアントプログラムです。


データサーキットを構成する必要がないので、connectは不要です。
sendtosendと同じ使い方をしますが、サーバーの情報を示す構造体のアドレスを渡す必要があります。

sendtoの第一引数へは、送出するソケットを指定します。
sendtoの第二引数へは、送出するパケットのアドレスを指定します。
sendtoの第三引数へは、どの位のデータを送信していいかを指定します。
sendtoの第四引数へは、基本的に0を指定します。ルーティングテーブルを迂回するか、データをバンド外で送信するかなどを指定できますが、あまり使いません。
sendtoの第五引数へは、サーバーの情報を示す構造体のアドレスを渡す必要があります。
sendtoの第六引数へは、第五引数のバイト単位の大きさを指定します。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
お疲れ様でした! これにてWinSock1, 2の学習は終了です。
補足なのですが、ネットワークの世界では機種、OSに依存せず通信を行うことができます。
つまり、Linux上でBSDSocketなどを使用して稼働しているサーバーサイドプログラムとクライアントプログラムの通信は全く問題なく行えます。
また、パケットの流動性を確認するにはWiresharkというソフトウェアを使用するとよいでしょう。

これからもネットワークの世界を駆け抜けて下さい。
このエントリーをはてなブックマークに追加

前回作成したDXライブラリのプログラムのことは忘れて下さい。
いつものコンソールへ戻りますよ。

さて、実は今まで作成してきたサーバーサイドプログラムには重要な欠陥があるのです。
それを見る為に、実験をしてみましょう。

クライアントプログラムから//sendを全てコメントアウトして下さい。
サーバーサイドプログラムを起動して、クライアントプログラムを起動します。
つまり、connectによるSYNしか送らないということです。

これを行うと……
19


例外が生成され、プログラムが強制的に停止しました。
このサーバーサイドプログラムは、SYNを送信した後、パケットを送信しなかった時、例外が発生するのです。
なぜなら、recvが失敗するからです。意外なことに、recvはソケットバッファからデータを読みだせなかった時、0ではなく-1を返します。読み出したデータのバイト数を返すのがrecvだと思っていたのですが、読みだせなかった時はエラー扱いなのです。

なので、
ClientDateBuffer[recvRETURN] = '\0';

NULL文字を格納する為のこの行にて、recvが-1を返した時は、
ClientDateBuffer[-1] = '\0';

となるのです。-1の領域へ書き込むなんて不可能ですから、例外が生成されるのですね。

という訳で、recvが-1を返した時の処理を考えましょう。これをエラー処理と言います。
ボクは単純に、
if (recvRETURN == -1) recvRETURN = 0;
 と書きました。
なぜなら、recvで文字を読みだせなかったのならば、0文字読み出した扱いの方が人間工学的に正しい気がしたからです。これなら
ClientDateBuffer[0] = '\0';
 で配列の先頭へNULL文字を格納し、その配列にデータがないことを表現できますね。


これなら例外が生成されることはなく、プログラムは問題なく動きます。
このように、関数の返す値を利用してエラーであるか否かを見極め、エラー処理をコーディングしていくことをエラー処理と言います。

各関数のエラーコードは……WinSockの関数のエラーコードは煩雑なので、各関数ごとに検索した方が早いと思います。
このエントリーをはてなブックマークに追加

この時間は、WindowsアプリケーションでWinSock1, 2を使用する方法を学びます。
Windowsアプリケーションに興味がない方はこの章を丸ごと飛ばして次の章へ移って下さい。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Windowsアプリケーションでwindows.hwinsock1, 2.hを併用する場合、あるマクロを定義する必要があります。
#define WIN32_LEAN_AND_MEAN


です。windows.hwinsock1, 2.hがインクルードするファイルは重複しているので、このマクロで重複したヘッダを省きます。

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>

こんな感じです。

ちなみにDXライブラリを使用する場合も同じです。DxLib.hは内部でwindows.hをインクルードしている為です。

#define WIN32_LEAN_AND_MEAN
#include "DxLib.h"
#include <winsock2.h>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
今回はDXライブラリを用いたWindowsアプリケーションでWinSock1, 2を使用する方法を学びます。
と言っても、これまでに学習してきたことと、上記のマクロを使うだけです。また、acceptの判定には非同期通知を使用します。

DXライブラリが分からない方は、この章を丸ごと飛ばして次の講義へ移るか、DXライブラリの勉強を別途行って下さい。http://dxlib.o.oo7.jp/


と言っても、実際は非同期通知を作成した時とほとんど同じコードになります。

実行結果
18

なお、送信側のプログラムはコンソールですが全く問題ないです。インターネットにあらゆるアプリケーションや機器が接続し、やり取りが可能なのは、通信プロトコルが統一されていることと、ネットワークバイトオーダーが定められているからです。環境は問題ではありません。
このエントリーをはてなブックマークに追加

↑このページのトップヘ