プロが教えるわが家の防犯対策術!

CのWindowsアプリケーションとしてソケット通信のプログラムを作って
います。
現在、1対1の社内パソコン同士で、一方のホスト名を手入力させることで
ソケット通信が可能な状態です。
-------------------------------------------------------------
クライアント側:サーバー側のホスト名を手入力で指定して接続

|接続

サーバー側:接続待ち
-------------------------------------------------------------
これを手入力の必要なく、自動で接続が行なわれるようにしたいです。
やり方を教えて頂けないでしょうか?

A 回答 (3件)

 30分ほどで簡単にコードを書いてみました。

なので、申し訳ありませんが動作未確認です。あくまで参考程度にご覧いただき、使用している関数の意味等についてはご自分でお調べいただければ幸いです。また、命令受信後にはホスト名を文字列として返していますが、当然ながらIPアドレス4バイトを返信してもOKです。
 ポイントは2点。(1) UDPソケット生成時には「SOCK_DGRAM」を使用する(TCPでは「SOCK_STREAM」)、(2) ブロードキャストアドレスとして"255.255.255.255"を指定する
 なお、下記のプログラムの構造でそのまま実行しようとした場合、select実行時に何らかのパケットを受信するまで確実にプログラムが停止します。正常動作するアプリケーションを作成されるのであれば、「UDP受信」「UDP送信」「TCP受信」「TCP送信」の各スレッドを生成する必要があります。

●参考サイト
Geekなぺーじ : UDPでブロードキャストを使う
http://www.geekpage.jp/programming/winsock/broad …
ソケットプログラミング
http://www.katto.comm.waseda.ac.jp/~katto/Class/ …

●仕様
・任意PCより、LAN内のPCに対してアプリケーションの有無を検索する側を「検索元側」と呼称する
・予めLAN内で起動しており、検索される側を「被検索側」と呼称する
・検索元側はUDPにより1バイトのホスト名要求命令を送信する
・ホスト名要求命令を受信した被検索側は、ホスト名を文字列として送信する
・通信ポート番号は12345とする
・被検索側のホスト名は"example.com"とする


// ========== 検索元側・被検索側共通マクロ ==========
#define REQUEST_HOST 0x01 // ホスト名要求命令
#define PORT_NUM 12345 // ポート番号


// ========== 検索元側ここから ==========
#include <winsock2.h> // Windows用なのでWinsock2をインクルード

// ----- 0.前準備 -----
// Winsock2初期化
WSADATA data;
WSAStartup (MAKEWORD (2,0), &data));

// ----- 1. UDPパケット送信 -----
// ソケット生成
SOCKET socUDP;
socUDP = socket (AF_INET, SOCK_DGRAM, 0);

// sockaddr_in構造体セット
struct sockaddr_in addrUDP;
memset (&addrUDP, 0, sizeof (addrUDP));
addrUDP.sin_port = htons (PORT_NUM); // ポート番号設定
addrUDP.sin_family = AF_INET;
addrUDP.sin_addr.s_addr = inet_addr ("255.255.255.255"); // ブロードキャストアドレス指定

// パケット送信
char szBuf[] = {REQUEST_HOST};
sendto (socUDP, szBuf, 1, 0, &addrUDP, sizeof (addrUDP));

// 送信完了
closesocket (socUDP);

// ----- 2. UDPパケット受信 -----
// ソケット生成
socUDP = socket (AF_INET, SOCK_DGRAM, 0);

// sockaddr_in構造体セット
memset (&addrUDP, 0, sizeof (addrUDP));
addrUDP.sin_port = htons (PORT_NUM); // ポート番号設定
addrUDP.sin_family = AF_INET;
addrUDP.sin_addr.s_addr = htonl (INADDR_ANY);

// バインド
int nStatus = bind (socUDP, (struct sockaddr_in *) &addrUDP, sizeof (addrUDP));

// selectで受信待機
fd_set fds;
FD_ZERO (&fds); // fd_set初期化
FD_SET (socUDP, &fds); // selectで待つ読み込みソケットを登録
select (socUDP +1, &fds, NULL, NULL, NULL); // UDPパケットを受信するまで待機

// 読み込み可能データ受信
char szBuf[256];
if (FD_ISSET (socUDP, &fds)) {
// ソケットからデータを受信
memset (szBuf, 0, 256);
int nRecv = recv (socUDP, szBuf, 256, 0);
// 受信データを表示(ホスト名のはず)
printf ("%s", szBuf);
}

// 受信完了
closesocket (socUDP);

// ここにTCP通信処理

// ----- 3.終了処理 -----
WSACleanup ( );


// ========== 被検索側ここから ==========
#include <winsock2.h> // Windows用なのでWinsock2をインクルード

// ----- 0.前準備 -----
// Winsock2初期化
WSADATA data;
WSAStartup (MAKEWORD (2,0), &data));

// ----- 1 UDPパケット受信 -----
// ソケット生成
SOCKET socUDP;
socUDP = socket (AF_INET, SOCK_DGRAM, 0);

// sockaddr_in構造体セット
struct sockaddr_in addrUDP;
memset (&addrUDP, 0, sizeof (addrUDP));
addrUDP.sin_port = htons (PORT_NUM); // ポート番号設定
addrUDP.sin_family = AF_INET;
addrUDP.sin_addr.s_addr = htonl (INADDR_ANY);

// バインド
int nStatus = bind (socUDP, (struct sockaddr_in *) &addrUDP, sizeof (addrUDP));

// selectで受信待機
fd_set fds;
FD_ZERO (&fds); // fd_set初期化
FD_SET (socUDP, &fds); // selectで待つ読み込みソケットを登録
select (socUDP +1, &fds, NULL, NULL, NULL); // UDPパケットを受信するまで待機

// 読み込み可能データ受信
char szBuf[256];
if (FD_ISSET (socUDP, &fds)) {
// ソケットからデータを受信
memset (szBuf, 0, 256);
int nRecv = recv (socUDP, szBuf, 256, 0);
// ホスト名要求命令でない場合はエラー終了
if (szBuf[0] != REQUEST_HOST) {
closesocket (socUDP);
return 1;
}
}

// 受信完了
closesocket (socUDP);

// ----- 2. UDPパケット送信 -----
// ソケット生成
socUDP = socket (AF_INET, SOCK_DGRAM, 0);

// sockaddr_in構造体セット
memset (&addrUDP, 0, sizeof (addrUDP));
addrUDP.sin_port = htons (PORT_NUM); // ポート番号設定
addrUDP.sin_family = AF_INET;
addrUDP.sin_addr.s_addr = inet_addr ("255.255.255.255"); // ブロードキャストアドレス指定

// パケット送信
char szBuf[256];
strcpy (szBuf, "example.com");// ホスト名設定
sendto (socUDP, szBuf, strlen (szBuf) + 1, 0, &addrUDP, sizeof (addrUDP));

// 送信完了
closesocket (socUDP);

// ここにTCP通信処理

// ----- 3.終了処理 -----
WSACleanup ( );
    • good
    • 0
この回答へのお礼

ご回答ありがとうございました。
身勝手な質問にもかかわらず、根気よく丁寧に答えて頂きまして
感謝の気持ちで絶えません。

お礼日時:2008/10/27 09:27

サーバー側が起動している事を条件として、以下の手順でしょうか。



1.ホスト名要求
  クライアント起動時にLAN内に「ホスト名要求命令」を
  UDPブロードキャストにて送信
2.ホスト名返信
  サーバがUDPパケットを受信、解析し、「ホスト名要求命令」である場合には
  サーバのホスト名を同じくUDPにて返信
3.ホスト名受信
  クライアントがUDPパケットを受信、解析し、サーバのホスト名を取得
4.TCPコネクション作成
  3にて取得したホスト名によりクライアント側にてTCPソケットを生成、
  connectする。以降の通信はTCPにより行う

もう少し賢いやり方(1でクライアント側ホスト名をサーバに通知し、2の段階でサーバ側からクライアント側にTCPで接続、など)があるかもしれませんが、だいたいこんな感じで出来るかと思います。
なお、各命令はクライアントとサーバであらかじめ取り決める命令で、同様にポート番号もあらかじめ相互に決定済みである必要があります。

この回答への補足

ご回答ありがとうございます。
もしよろしければ
1~3までの手順のソース(C言語)を載せて頂けたら大変助かります。
いろいろ検索してみたのですが、どうにもわからなくて……
どうかよろしくお願い致します。

補足日時:2008/10/23 16:50
    • good
    • 0

自動とは、どういった動きを期待していますか?



例えば、サーバー端末が1台のみで固定であれば、あらかじめ、そのホスト名を保持しておけば言い訳ですし、逆に複数のサーバー端末が存在する場合、複数のサーバーのうち、どれに接続すべきかという条件がなければ、一意のサーバーに接続することは難しいと思います。

この回答への補足

ご回答ありがとうございます。
説明不足で申し訳ありません。

同じLANで繋がっている複数のパソコン同士が、ユーザーによる手入力を必要とせず、プログラムから自動的にLANに接続されているパソコン全てのホスト名を取得および表示できるようなふうにしたいです。
「IP Messenger」http://www.ipmsg.org/
というフリーソフトが正にそうなっておりまして、exeファイルを起動させるだけで、同じLAN内のパソコンであれば勝手にLAN内のパソコンのホスト名を取得して表示してくれます。
(こちらのソフトはソースが公開されていますが、解析しようと試みたところまるで歯が立ちませんでした)

こういった機能はどのようにしたら実現できるのでしょうか?
ご指導頂けたら幸いです。

補足日時:2008/10/22 00:56
    • good
    • 0
この回答へのお礼

ご回答ありがとうございました。
大変助かりました。

お礼日時:2008/10/27 09:23

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています