Sock-07.てきとう掲示板
今回のお題
TCPで掲示板風のものをつくろう!
今回のプログラムは
コンソールアプリケーション ※DxLibは使わない!
TCP
サーバは複数クライアントから文字列を受信→出力
一応3クライアントでいく!
クライアントはサーバに文字列を送信
サーバ
1. ヘッダ・ライブラリ~WinSockの初期化と終了処理
必要なヘッダインクルードしたり、ライブラリを追加したりする
WinSockの初期化処理と終了処理を書く
code:Server04.cpp
int main()
{
// WinSockの初期化処理 WinSock2.2
// WinSockの終了処理
return 0;
}
2. TCP リスンソケットの作成とリスンソケットの破棄
code:Server04.cpp
int main()
{
// WinSockの初期化処理 WinSock2.2
// TCPリスンソケットの作成
// TCPリスンソケットの破棄
// WinSockの終了処理
return 0;
}
3. リスンソケットに固定ポート番号割り当て
code:Server04.cpp
int main()
{
// WinSockの初期化処理 WinSock2.2
// TCPリスンソケットの作成
// SOCKADDR_IN構造体に各種設定
// bind
// TCPリスンソケットの破棄
// WinSockの終了処理
return 0;
}
4. リスンソケットをリスン状態に設定
code:Server04.cpp
int main()
{
// WinSockの初期化処理 WinSock2.2
// TCPリスンソケットの作成
// SOCKADDR_IN構造体に各種設定
// bind
// listen
// TCPリスンソケットの破棄
// WinSockの終了処理
return 0;
}
5. クライアントからの接続要求を待つ
今回はいったん3クライアントに固定...マジックナンバーを使って嫌な気持になる
SOCKET型の配列要素数3を用意して、ループでaccept()すればok
ついでに、3クライアントとのコネクション切断とソケット破棄もかいとこう
code:Server04.cpp
int main()
{
// WinSockの初期化処理 WinSock2.2
// TCPリスンソケットの作成
// SOCKADDR_IN構造体に各種設定
// bind
// listen
// 3クライアント用のソケットを用意
SOCKET socks3; // 嫌な気持ちになる3 // 3クライアント用のソケットアドレス構造体を用意...クライアントのアドレスも使いたくなるかもしれないから
SOCKADDR_IN clientSocketAddresses3; // 3クライアントからの接続要求を待つ
int clientCount = 0;
while( clientCount < 3 )
{
// いったんSOCKET型の変数に入れて…
SOCKET tmpSock = accept( listenSock, (SOCKADDR *)&clientSocketAddressesi, ~ ); if( tmpSock == INVALID_SOCKET )
{
// 接続要求受付エラー
}
else
{
// 接続要求受付たら、3クライアント用のソケット配列にセットする
clientCount++;
}
}
// 3クライアント切断・ソケット破棄
for( int i = 0; i < 3; i++ )
{
shutdown( socksi, SD_BOTH ); }
// TCPリスンソケットの破棄
// WinSockの終了処理
return 0;
}
6. クライアントからの文字列受信→出力
今回は0→1→2の順に受信・出力を繰り返す
recv()でブロッキングが発生するので、順番は飛ばせない
code:Server04.cpp
int main()
{
// WinSockの初期化処理 WinSock2.2
// TCPリスンソケットの作成
// SOCKADDR_IN構造体に各種設定
// bind
// listen
// 3クライアント用のソケットを用意
SOCKET socks3; // 嫌な気持ちになる3 // 3クライアント用のソケットアドレス構造体を用意...クライアントのアドレスも使いたくなるかもしれないから
SOCKADDR_IN clientSocketAddresses3; // 3クライアントからの接続要求を待つ
int clientCount = 0;
while( clientCount < 3 )
{
// いったんSOCKET型の変数に入れて…
SOCKET tmpSock = accept( listenSock, (SOCKADDR *)&clientSocketAddressesclientCount, ~ ); if( tmpSock == INVALID_SOCKET )
{
// 接続要求受付エラー
}
else
{
// 接続要求受付たら、3クライアント用のソケット配列にセットする
clientCount++;
}
}
// 受信・出力部
while(1)
{
for( int i = 0; i < 3; i++ )
{
int ret = recv( socksi, ~ ); if( ~ )
{
// エラー
}
else
{
// 受信文字列の出力
}
}
}
// 3クライアント切断・ソケット破棄
for( int i = 0; i < 3; i++ )
{
shutdown( socksi, SD_BOTH ); }
// TCPリスンソケットの破棄
// WinSockの終了処理
return 0;
}
おまけ
SOCKADDR_IN構造体のsin_addrに入っているIPアドレス( in_addr構造体 )を人間がよく使う文字列に直すには…inet_ntop()を使う ※inet_ntoa()が楽だった
IPv4アドレスはxxx.xxx.xxx.xxxの形式なので、最大15文字 + \0で16個分のchar型配列
code:sample.cpp
SOCKADDR_IN socketAddress; // ソケットアドレス構造体
char ipAddress16; // IPアドレス( 文字列 ) // accept()に成功するとsocketAddressにクライアントのソケット情報が入る
int ret = accept(~, (SOCKADDR *)&socketAddress, ~);
// socketAddress.sin_addrを文字列にしてipAddressに格納
inet_ntop( AF_INET, &socketAddress.sin_addr, ipAddress, sizeof(ipAddress) );
TCPクライアント
ソケット作って、接続要求だす
文字列入力→送信
注意
ブロッキングが発生するので、変な感じの動作になるでしょう!
気になる場合は、サーバが受信後に返信するとよいでしょう