- PR -

.Net Frameworkのソケット通信のSDKについて初歩的な質問

投稿者投稿内容
Qoo
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 121
投稿日時: 2004-07-03 15:33
こんにちは。

問題作成時には、Q1 ○ Q2 × Q3 ○ Q4 × Q5 ○ と考えてたのですが、
あれこれ調べ直してみると、Q3 については×もありうるような。。。(^^;
(問題に不備があるというやつですか)

私の認識(間違いも多々あると思いますが)では、サーバ側で開かれる
ポート番号に対しては複数のクライアントから同時接続が可能だと
思っています。

同時に接続要求があった場合、Acceptの処理が済んでいないものに
ついては、Listenで確保したキューの中に置かれます。
接続要求は一旦キューに置かれ、Acceptで取り除かれる、という方
が正しいのかも。
(Acceptさせずに、Listenで確保したキューを一杯にした状態で
新たなクライアントから接続しようとすると、接続拒否のエラーが
返ってたような気が。。。)


Q3の不備については、
サーバ側で同じポート番号を複数開くことはできない、という認識
だったのですが、『同じプロトコル』ではできないけど
『違うプロトコル』であれば同じポート番号を複数開くことは可能
のようです。
なので、ソケットの接続待ち受けをするプログラムが違うプロトコル
で同じポート番号を割り当てる仕組みになっていれば、起動できて
しまうということに。。。
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-07-03 17:04
諸農です。

純粋に疑問を感じたのですが。

引用:

Q3の不備については、
サーバ側で同じポート番号を複数開くことはできない、という認識
だったのですが、『同じプロトコル』ではできないけど
『違うプロトコル』であれば同じポート番号を複数開くことは可能
のようです。



例えば、110番ポートでPOP3をサポートするアプリと
SMTPをサポートするアプリの両方が待機できたとして、
110番に接続したクライアントは、どのようにしてPOP3と
SMTPの使い分け、または接続したいサーバーサービスの
選択をどのようにすればいいのでしょうか?

_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
Izumi, Y.
ベテラン
会議室デビュー日: 2002/03/19
投稿数: 77
お住まい・勤務地: 東京
投稿日時: 2004-07-04 18:39
ここでいうプロトコルは POP3,SMTP といったアプリケーション層のプロトコルではなくて,TCP,UDP といったトランスポート層のプロトコルでは.
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-07-05 00:57
引用:

ここでいうプロトコルは POP3,SMTP といったアプリケーション層のプロトコルではなくて,TCP,UDP といったトランスポート層のプロトコルでは.



あ、なるほど。
1ポートにつきTCPとUDPでそれぞれ1個ずつ(トータルで2個)利用という事ですね。
その意味であれば納得できます。

_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-07-05 01:13
諸農です。

引用:

自分としては、こんな例を整理してくれて、かつ、マンガ絵みたいなので示している
書籍を探してます(^^;



次の2冊ですが、絵は少なかったですが思った以上にサンプルコードが多く、
同期非同期、ブロッキング、スレッディングについても詳しく書かれていました。

C# Network Programming
 Richard Blum
 ISBN:0782141765

TCP/IP SOCKET IN C#
 David Makofske
 ISBN:0124660517

--追加--
今月(7月3日)発売のドットネットマガジンの
「.NET Frameworkアイデアノート」という連載で
「マルチスレッドTCP/IPサーバーを作る」という表題の
記事が掲載されています。

#投稿した後になにげに雑誌のページをパラパラめくって、
#気付きました。私自身、今から読むところなのですが、
#もしかしたら上記の2冊と同様、参考になるかもしれません。


_________________
諸農和岳
Powered by Borland Delphi/C++Builder & Microsoft VS.NET

[ メッセージ編集済み 編集者: Jubei 編集日時 2004-07-05 01:25 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-07-05 08:52
 たまたま古いデータの入ったHDDが見つかりました。そこに、1999年に作ったシステムのソースがありました。
 これで書いた技術報告書もありまして、そこで「マルチタスクだと1秒間に60程度しかプロセスの起動ができない。マルチスレッドだと120のスレッドを起動できた」と書いてあるので、マルチスレッドで行っています。ただし、Solarisです。Windowsだと、70程度で頭打ちになった記憶があります。

システムの概要:
 サーバは着信を待つ。着信があると、データを受け取り、音声認識ライブラリへデータを引き渡す。音声認識ライブラリからの戻り値を、クライアントに引き渡す。
 要求性能は、1時間あたり4万件のデータ処理。音声データの長さ、音声認識ライブラリの性能を考えると、1秒間に112件のデータ処理。

ソース:
コード:
main(int argc, char **argv)
{
	int	*arg;
	struct sockaddr	cltAddr;
	pthread_attr_t	threadAttr;
	pthread_t	sthread;

	if ((sts = initialize(argc, argv)) != NoError) {
	}

	/* 音声取得ボードを初期化する */
	InitCTA();

	/* リンガーオプション用の値作成 */
	linger.l_onoff = 1;     /* リンガーオン */
	linger.l_linger = 0;    /* チェック時間 */

	/* ソケットを生成する */
	if ((sofd = C_createSocket("ivr-vgw", hostID, &eno)) < 0) {
	}

	addrlen = sizeof(struct sockaddr);
	while (TRUE) {
		if ((clfd = accept(sofd, &cltAddr, &addrlen)) < 0) {
		}
		setsockopt(sofd, SOL_SOCKET, SO_LINGER,
			(char *) &linger, sizeof(struct linger));
		if ((arg = (int *) malloc(sizeof(int))) == NULL) {
		}
		*arg = clfd;
		/* スレッドを生成する */
		tid = pthread_create(&sthread, NULL, voiceGet, (void *) arg);
                if (tid != 0) {
		}
	}

	exit(-1);
}


注目はacceptです。
if ((clfd = accept(sofd, &cltAddr, &addrlen)) < 0)
ここで、sofdは入力引数で、上(C_createSocket関数内)で作ったファイルディスクリプタ(WindowsではSOCKET構造体が相当)を渡します。戻り値は"新しい"ファイルディスクリプタ(WindowsではSOCKET構造体)です。この"新しい"とは、servicesファイル(WindowsXPではSYSTEM32/drivers/etecディレクトリ内)に定義されておらず、現在開いていないポートが使われます(そういうことだったと思う)。

 例えば、80番(HTTP)のポートで待っている(accept)とします。ここにクライアント1がアクセスを行います。すると、acceptは、例えば81番のポートにリクエストを複製し、復帰します。すると、クライアント2は80番のポートにリクエストを投げることができます(QooさんのQ1が○)。しかし、復帰する前(複製中など)であるなら、クライアント2の80番に対するリクエストは拒否されます(Q2の×)。複製後、80番のポートは空きますので、次のリクエストはキューに入れられます(2004-07-03 15:33の発言中で言明)。このプログラムでは、スレッド生成後にすぐacceptしますので、キューの先頭がまた複製されます。マルチスレッドや、マルチタスクになっていない場合、acceptが呼ばれるまで、キューにたまり続けます。キューからあふれると、クライアントがエラーを生成します。

 私のプログラムに戻って、複製されたポートはargにコピーして、pthread_create関数により、voiceGet関数が新規スレッドとして起動されます。voiceGet関数にて、次の処理を行います。
ソース:voiceGet関数(長いので要所のみ)
コード:
static void *
voiceGet(void *fdp)
{
	int	fd;			/* 通信用ファイルディスクリプタ */

	/* 引数受け取り */
	memcpy((char *) &fd, (char *) fdp, sizeof(int));
	free(fdp);

	/* ヘッダ受け取り */
	sts = C_RecieveMessage(fd, (char *) &header,
			sizeof(DataHeader), 10);
	/* データ受け取り */
	sts = C_RecieveMessage(fd, (char *) &request,
			sizeof(VoiceGetRequest), 10);

	/* ヘッダ送信 */
	sts = C_sendMessage(fd, (char *) &header, sizeof(DataHeader), 10);
	/* データ送信 */
	sts = C_sendMessage(fd, (char *) &replay, header.DataSize, 10);

	/* 回線を閉じ、スレッドを終了する */
	close(fd);

	/* デタッチ */
	pthread_detach(pthread_self());
	pthread_exit((void *) &sts);
}


このように、複製されたファイルディスクリプタで、クライアントとの通信処理を行っています。このとき、クライアントアプリケーションは、おそらく81番のポートとやりとりをしているとは知りません。クライアントも80番に対して開いて、そのファイルディスクリプタをライブラリから受け取っているので、ポート番号は意識せず、"通信口"に対して処理を行っていると思います。


注意:このプログラムはSolaris用なので、Windowsでは動作しません。

#voiceGetといいながら、判別もやってるし。。。
#命名もめちゃくちゃだし。。。
#そういうツッコミが入れられるということは、成長しているということ、
#と、納得しておこう。。。
隣の古柴
ベテラン
会議室デビュー日: 2004/06/04
投稿数: 94
投稿日時: 2004-07-05 10:09
半人前です。お世話になっております。
Jubeiさん、レスありがとうございます。

引用:

次の2冊ですが、絵は少なかったですが思った以上にサンプルコードが多く、
同期非同期、ブロッキング、スレッディングについても詳しく書かれていました。



机で小躍りしたのもつかの間、英文ですね(((^^;
ですが、ありがとうございます。

引用:

--追加--
今月(7月3日)発売のドットネットマガジンの
「.NET Frameworkアイデアノート」という連載で
「マルチスレッドTCP/IPサーバーを作る」という表題の
記事が掲載されています。




とりあえずこっちに飛びつきます(((((^^;
隣の古柴
ベテラン
会議室デビュー日: 2004/06/04
投稿数: 94
投稿日時: 2004-07-05 12:56
自己レスです。

引用:

引用:

--追加--
今月(7月3日)発売のドットネットマガジンの
「.NET Frameworkアイデアノート」という連載で
「マルチスレッドTCP/IPサーバーを作る」という表題の
記事が掲載されています。




とりあえずこっちに飛びつきます(((((^^;




書店に行って斜め読みしたところ、欲しているソケットレベルでの解説ではありません
でした・・残念です。

スキルアップ/キャリアアップ(JOB@IT)