ネットワークプログラミング相談室 Port21
■ このスレッドは過去ログ倉庫に格納されています
0001echoちゃん
2008/02/29(金) 21:19:37Programming UNIX Socket FAQ (日本語訳)
http://www.kt.rim.or.jp/~ksk/sock-faq/indexj.html
Winsock Programmer's FAQ (日本語訳)
http://www.kt.rim.or.jp/~ksk/wskfaq-ja/
関連リンクは>>2-10辺り
足りなかったら適当に付け足してね
前スレ
ネットワークプログラミング相談室 Port20
http://pc11.2ch.net/test/read.cgi/tech/1186418855/
関連スレ
Java ネットワークプログラミング 【教えて!】
http://pc11.2ch.net/test/read.cgi/tech/1086238859/
0322デフォルトの名無しさん
2008/06/11(水) 12:27:03小人さんは間違いが多いのが欠点だ。
0323デフォルトの名無しさん
2008/06/13(金) 22:24:38近い将来、サーバー側、クライアント側で行う動作を基底クラスで実装して、それぞれのクラスを派生させようと思うが、サーバー側とクライアント側で
何が共通手順なのか、今はまだよく分からないので、とりあえず前に進めるためおこなっていおる
どうよこんな感じで
class Socket {
int fd1, fd2;
struct sockaddr_in saddr;
struct sockaddr_in caddr;
int len;
public:
Socket() : fd1(0), fd2(0), len(0) {} // コンストラクタ
~Socket(){} // デスクトラクタ
void MakeSocket(); // ソケット生成
void InitSocket( sockaddr_in saddr) ; // ソケット初期化
void NameOfTheSocket( sockaddr_in saddr );// ソケットに名前を代入
void BindSocket( sockaddr_in saddr ); // ネームバインド
void ListenSock( int fd1 ); // リッスン
void AcceptSocket(); // アスペクト
void CloseSocket(); // ソケットクローズ
};
0324デフォルトの名無しさん
2008/06/13(金) 22:24:59void Socket::MakeSocket()
{
if ((fd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
}
void Socket::InitSocket( sockaddr_in saddr )
{
memset((char *)&saddr, 0, sizeof(saddr));
}
void Socket::NameOfTheSocket( sockaddr_in saddr )
{
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(PORT);
}
void Socket::BindSocket( sockaddr_in saddr )
{
if (bind(fd1, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){
perror("bind");
exit(1);
}
}
void Socket::ListenSock( int fd1 )
{
if ( listen(fd1, 1) < 0) {
perror("listen");
exit(1);
}
}
0325デフォルトの名無しさん
2008/06/14(土) 06:51:370326デフォルトの名無しさん
2008/06/14(土) 07:58:40sockaddrはラップして、アドレスのクラスを作ってしまう。簡単にアドレスを設定できるようにするといい。
あと、言葉遣い直せ
0327デフォルトの名無しさん
2008/06/14(土) 08:00:05ソケットクラスの構成をみれば〜?
0328デフォルトの名無しさん
2008/06/14(土) 08:27:18君はまずその変な日本語を直さないとな
他人の言葉遣いを指摘してる場合じゃないぞ
0329デフォルトの名無しさん
2008/06/14(土) 09:27:20こんな感じで、完成形に徐々に近づきつつあると思うが、どうよ
class Socket {
struct sockaddr_in saddr;
struct sockaddr_in caddr;
public:
Socket(){} // コンストラクタ
~Socket(){} // デスクトラクタ
void SetAddresSocket( sockaddr_in saddr, unsigned short sock_family, unsigned short sock_port, int sock_addr ); // sockaddrラッパークラス
int DescriptSocket(); // ソケットを作り、成功したらソケットディスクリプタを返す
};
0330デフォルトの名無しさん
2008/06/14(土) 09:27:56{
saddr.sin_family = sock_family;
saddr.sin_addr.s_addr = sock_port;
saddr.sin_port = htons( sock_addr );
}
int Socket::DescriptSocket()
{
int fd1, fd2;
size_t len;
if ((fd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset((char *)&saddr, 0, sizeof(saddr)); // 初期化
// バインド
if (bind(fd1, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){
perror("bind");
exit(1);
}
if ( listen(fd1, 1) < 0) {
perror("listen");
exit(1);
}
len = sizeof(caddr);
if ((fd2 = accept(fd1, (struct sockaddr *)&caddr, &len)) < 0) {
perror("accept");
exit(1);
}
close(fd1);
return fd2;
}
0331デフォルトの名無しさん
2008/06/14(土) 09:34:50accept()関数の第三引数の
accept(fd1, (struct sockaddr *)&caddr, &len))
lenだが、VC8ならintでも無問題なのだけど、g++はsize_tじゃないと嫌だと
怒ったりとかと少し戸惑う、>>330でした
0332デフォルトの名無しさん
2008/06/14(土) 09:54:59size_tとしてしまうのは誤り。
socklen_tとint(やsize_t)が同じサイズか判定をどこかに入れておくと安全。
// 偽なら負の添え字になりコンパイルエラー
#define STATIC_ASSERT(cond) extern int static_assert_array[ (cond) ? 1 : -1 ];
STATIC_ASSERT(sizeof(int) == sizeof(socklen_t))
0333デフォルトの名無しさん
2008/06/14(土) 10:05:46Thx
物知りですね、勉強になります
gccの場合、accept()関数の第三引数は、int型でコンパイルに成功してたんだけど、g++でコンパイルした際にエラーが出たんで
なんでかなと思ってた、コンパイラに依存しないようにアサーションマクロを書いておくと、メモメモ
0334デフォルトの名無しさん
2008/06/14(土) 14:25:52selectでウインドウハンドルとそのウインドウのプロシージャを設定するけど
最初はウインドウAでメッセージ受けてたけど
次はウインドウBでメッセージ受けるように変更
とかいうことはできますか?
本当はウインドウハンドル指定しなくてよければ通信メッセージ受けるところだけ独立させたいんだけど
0335デフォルトの名無しさん
2008/06/14(土) 14:32:58WSAEventSelectを使えばウインドウハンドルはいらない。
0336デフォルトの名無しさん
2008/06/14(土) 14:35:32お〜 ウインドウハンドルいらない版もありましたか
ありがとうございまつ
0337デフォルトの名無しさん
2008/06/14(土) 16:12:06gethostbynameではwinsockが確保したメモリが返されてきますが
これはどうすると解放できるのでしょうか?
0338デフォルトの名無しさん
2008/06/14(土) 16:17:39gethostbynameでググルと一番上に解説が出てくるし
0339デフォルトの名無しさん
2008/06/14(土) 20:59:48>>327
が書いてたんで、rubyのソケットのライブラリを見てたら、やっぱ個別に
sockの関数と1対1に対応するメソッドを持ってるよね
>>326は
1対1に対応するメソッドを作ると、恩恵は受けにくいと言うし
ネットワークプログラミングとは直接関係ないけど、どっちがいいんだろうな?
この問題にはいつも悩まされる
永遠の命題なのか・・・・orz
0340デフォルトの名無しさん
2008/06/14(土) 21:10:21たとえば、自分向けのライブラリを作るなら、いきなりconnectで繋がって、closeで閉じるライブラリを作り置きしておくと、今後ずっと楽になる。
0341デフォルトの名無しさん
2008/06/14(土) 21:19:02わかりやすい説明、ありがとう
たしかに、それは言えるのだけど、ついつい、かまえてって言うか、型にはめようとして
再利用性だとか、拡張性だとか、考えてしまいクラスの設計には、いつも苦労するんだよね、俺の場合
もう少し気楽に考えた方がいいかもね
0342デフォルトの名無しさん
2008/06/14(土) 21:26:20共通の機能は基本クラスに、専用の機能は派生クラスに分散。一つのクラスで機能を欲張らないのが設計のコツ。
0343デフォルトの名無しさん
2008/06/14(土) 21:27:55C/C++で書いてるんなら、いつでも下に降りられるから、ある意味
どうでもいい気がする。
rubyみたいな奴だと、標準で抽象度の高いAPIしか用意されてないと
そこより下に降りたければCでextension書くしかないって話になる。
だからそういう設計になってるんだと思うよ。
0344デフォルトの名無しさん
2008/06/14(土) 21:34:17皆さん、いい話ありがとう
0345デフォルトの名無しさん
2008/06/14(土) 23:34:33思いますが、その後すぐにその問題が解決したら、相手側には届くのでしょうか?
0346デフォルトの名無しさん
2008/06/14(土) 23:36:06いつか届く。
0347デフォルトの名無しさん
2008/06/15(日) 04:36:590348デフォルトの名無しさん
2008/06/15(日) 06:09:21”こんにちわ” ”こんばんわ”
を相手が送信したときに
2つのメッセージに対して
FD_READが2回発生するときと
1回しか発生しないときがあります
2回発生するときは
”こんにちわ” と ”こんばんわ” を別々に取得できて問題ないのですが
1回しか発生しないときは
”こんにちわこんばんわ”という1つの文字になってしまいます
送信相手が1回送信するごとにFD_READが1回発生するように設定することはできますか?
できないとして1送信ごとに何らかの記号をつけて識別したりするのでしょうか?
0349デフォルトの名無しさん
2008/06/15(日) 06:29:10あと、どーでもいいけど「こんにちは」と「こんばんは」だと思う。
0350デフォルトの名無しさん
2008/06/15(日) 10:57:00SCTP。
おまいら使ってる?
0351デフォルトの名無しさん
2008/06/15(日) 14:04:34そもそも
「こ」「ん」「に」「ち」「わ」と5回に分かれてFD_READが来ることだってありえるぞ。
TCPとはそういうもんだ。区別したけりゃストリームに自前で区切情報載せろ
0352デフォルトの名無しさん
2008/06/15(日) 15:09:49ありなとうございまつ
Sendの末尾に区切り文字入れれば
1回で複数受信してもOKじゃね?
とか思ったけど1送信あたりでも分離することあるのですかorz
しかしそうなると
「こんに」「こんばんわ」「ちわ」という受信すらありえるような
それともTCPは受信順番も考慮するからそれはないと思っていいんでしょうか?
0353デフォルトの名無しさん
2008/06/15(日) 15:32:35必ずしも送った順に相手に届くとは限らない
この辺はUDPとTCPの違いを調べれば分かる
0354デフォルトの名無しさん
2008/06/15(日) 15:58:37TCPは順番は変わらないよ!。
0355デフォルトの名無しさん
2008/06/16(月) 11:35:18thread1(){ send("ABCDE"); }
thread2(){ send("abcde"); }
の2つのスレッドが同時にsendをコールした場合、
相手側でrecvした時に、
"ABCDE"と、"abcde"が混ざることってありますか?
例えば、"AaBbCcDdEe"みたいに。
シングルスレッドな場合だと、
send単位で送ったデータはそのまま出て来ますよね。
0356デフォルトの名無しさん
2008/06/16(月) 11:50:150357デフォルトの名無しさん
2008/06/16(月) 11:52:11どこから持って来てるんでしょうか?
(同じ情報を自分のプログラムから取得するにはどうすればいいでしょうか?)
2. TDImonか同等のプログラムのソースコードはどこかにないでしょうか?
0358デフォルトの名無しさん
2008/06/16(月) 11:53:480359デフォルトの名無しさん
2008/06/16(月) 11:59:56>"ABabcdeCDE"
これもありうる?
カーネルの中のソケット毎の送信バッファってのは、1つだよね。
複数のスレッドがsendをコールすると、その送信バッファに、
送信データが詰め込まれて行くんだと思うんだけど、
それがsend単位に区切られて詰められない可能性もあるってこと?
こういう動きって、OS依存?
send実行中に、スレッドがコンテキストスイッチしたらこうなるってこと?
2このスレッドが、同時に100Mバイトとかのデータをsendしたら、
そうなりそうな気がしないわけじゃないけど。
0360デフォルトの名無しさん
2008/06/16(月) 12:04:110361デフォルトの名無しさん
2008/06/16(月) 12:09:290362デフォルトの名無しさん
2008/06/16(月) 12:50:47確かにおっしゃる通りですね。
ってことは、やっぱりそうなる事もありうるってことですか。
0363デフォルトの名無しさん
2008/06/16(月) 19:19:51実装依存だろうし、起きるかどうか考えるだけ無駄
0364デフォルトの名無しさん
2008/06/16(月) 21:45:500365デフォルトの名無しさん
2008/06/16(月) 21:51:180366デフォルトの名無しさん
2008/06/16(月) 22:11:13どういった理由からですか?保障されているんですか?
0367デフォルトの名無しさん
2008/06/16(月) 23:13:06スレッド関係なしに。
だから、逐次処理で
send( "ABCDE" );
send( "abcde" );
とかやっても、相手側で
abcdeABCDEと受信することも普通にある。
0368デフォルトの名無しさん
2008/06/16(月) 23:19:200369デフォルトの名無しさん
2008/06/16(月) 23:22:45え??
0370デフォルトの名無しさん
2008/06/16(月) 23:30:040371デフォルトの名無しさん
2008/06/16(月) 23:37:42まぁ、どの実装でも、自前でコントロールすべしって結論になると思う
0372デフォルトの名無しさん
2008/06/16(月) 23:39:360373デフォルトの名無しさん
2008/06/16(月) 23:47:19システムフリーズするだけだな。
0374デフォルトの名無しさん
2008/06/17(火) 01:51:31順番がかわるとか複製される可能性があるのはUDPじゃないの?
おれなんか間違ってること言ってる?
手元の参考書にそう書いてあるんだけど?
0375デフォルトの名無しさん
2008/06/17(火) 01:56:01バーカ >>374
0376デフォルトの名無しさん
2008/06/17(火) 02:01:15スレ監視し続けてたんだね
お疲れ様
釣れて良かったね
おめでとう
0377デフォルトの名無しさん
2008/06/17(火) 02:46:29普通に起こるだろ。
シグナルだって入るし、場合によっちゃスレッドだってスイッチする。
0378デフォルトの名無しさん
2008/06/17(火) 04:08:33I/Oだったら普通にキューにぶっこんでコンテキストスイッチしないかな?
0379デフォルトの名無しさん
2008/06/17(火) 04:28:02connectのみ
WSAWaitForMultipleEventsでタイムアウトを判断して
send、recvはsetsockoptを使って指定、
これで大丈夫でしょうか?
0380デフォルトの名無しさん
2008/06/17(火) 08:52:260381デフォルトの名無しさん
2008/06/17(火) 09:58:450382355
2008/06/17(火) 10:05:16シングルスレッドの場合でしょ、それは絶対にあり得ないと思うんだけど。
最近のカーネルは、カーネルプリエンプションだから、カーネル内部の処理
実行中にコンテキストスイッチすることもあるかも知れないけど、
ロジックの実行順序(逐次処理)が入れ替わることはないと思います。
>>373
それとはまた別の話ではないでしょうか。
sendを呼んだひとはブロックされるでしょうが、他のプロセスは
普通にシステムコールを実行することも、ユーザーランドのロジックも
実行できると思います。
>>374
私もそういう認識です。
TCPで1つのスレッドが送信した場合であれば、sendした順に相手側では
recv出来ると思ってます。(何回recvすれば良いかは判らんけど。)
途中でパケロスしたり、物理的に線が切れたりした場合は、受信側に届いた
部分まで(これも、相手がsendした順)が受信出来る。
なにか間違ってます? >> all
0383デフォルトの名無しさん
2008/06/17(火) 16:49:350384デフォルトの名無しさん
2008/06/17(火) 17:04:560385デフォルトの名無しさん
2008/06/17(火) 17:14:260386デフォルトの名無しさん
2008/06/17(火) 17:23:550387デフォルトの名無しさん
2008/06/17(火) 17:54:230388デフォルトの名無しさん
2008/06/17(火) 18:07:41自作の俺プロトコルアプリが低速回線環境でどういった影響を受けるのか調べたいのですが。
環境はWindowsです(98orXP)
0389デフォルトの名無しさん
2008/06/17(火) 19:19:430390デフォルトの名無しさん
2008/06/17(火) 19:50:44TCPでそれがあったら大変だろ
UDPでは十分ありうるだろうが
UDPは順序がかわるどころか
複製されたりもするらしいからな
しかしUDPって順序も保障されてないとなると
1パケットあたりの情報をどうやって認識するんだろうか
区切り文字やらパケットサイズ送っても
順序がかわったりしたらアウトだよな?
0391デフォルトの名無しさん
2008/06/17(火) 20:41:210392デフォルトの名無しさん
2008/06/17(火) 21:56:192つ以上のパケットをもってきて、その関連をどうこういうと面倒だけど。
0393デフォルトの名無しさん
2008/06/18(水) 09:28:59例えば、
(1)udp_send("ABCD");
(2)udp_send("abcd");
とした場合、(1)で作成されたUDPパケットが相手HOSTに到達
するルートと、(2)で作成されたUDPパケットが相手HOSTに到達
するルートが同じだとは限らないですよね。
たまたま、(2)のUDPパケットが相手HOSTに到達するルートの方が
速い回線だったりした場合、受信側のHOSTでは、(2)(1)の順に
UDPパケットを受信する事もあり得ます。
UDPパケット毎の順序は不定ですが、複数のUDPパケットが混ざる
事はありません。(シングルスレッドの場合)
で、複製されるってのはどういう意味?
0394デフォルトの名無しさん
2008/06/18(水) 17:14:46とかが2回以上あったかのように
複数回届くことかと思われ
で、実際そういうことがある
パケットにインデックスとかつけて
2回目以降のやつは棄てればいいので問題ない
0395デフォルトの名無しさん
2008/06/18(水) 17:22:56それって UDP側じゃなくて MAC側の仕様じゃないの?
結果は同じだけど・・・
細かすぎるか?w
0396デフォルトの名無しさん
2008/06/18(水) 17:48:55重複するってのはなぜ?
誰がパケットを複製するの?
マルチキャストであればルータがパケットを複製するってのは
判るんですが。
0397デフォルトの名無しさん
2008/06/18(水) 17:59:51勝手に複製されてしまうこともあるって事ですか。
man ping より
重複パケットと障害パケット
ping ユーティリティは重複パケットと障害パケットを報告します。重複パケット
はユニキャストアドレスに対しては起こるはずのないものですが、リンク層での
不適切な再送信によって引き起こされるようです。重複は様々な状況で起こる可
能性があります。低いレベルの重複の存在は必ずしも警告にならないかもしれま
せんが、よい兆候ではありません。ブロードキャストもしくはマルチキャストア
ドレスに ping する時には、重複が起こることが期待されます。実際に重複する
のではなく、異ったホストから同じ要求に対して応答が行われからです。
障害を受けたパケットは明らかに重大な警告です。多くの場合、ping パケットの
経路のどこか (ネットワーク内かホスト内) のハードウェアの故障が考えられま
す。
0398デフォルトの名無しさん
2008/06/18(水) 18:03:13ないってことですね。
ただ、TCPだと、勝手に捨ててくれるけど、UDPだとそのまま
複数回受信しますということね。
と、なっとくしました。
考え方が間違ってたら、指摘してもらえると嬉しいです。
0399デフォルトの名無しさん
2008/06/20(金) 09:04:55不満を言う余裕はあるくせに
戦争する暇もある
0400デフォルトの名無しさん
2008/06/20(金) 21:50:000401デフォルトの名無しさん
2008/06/21(土) 18:36:220402デフォルトの名無しさん
2008/06/21(土) 19:43:200403デフォルトの名無しさん
2008/06/22(日) 03:08:020404デフォルトの名無しさん
2008/06/23(月) 01:42:100405デフォルトの名無しさん
2008/06/23(月) 01:55:060406デフォルトの名無しさん
2008/06/23(月) 22:27:500407デフォルトの名無しさん
2008/06/23(月) 22:43:10動かすことは可能でしょうか?
コンパイルは通ったのですが、実行するとうまく動きません。
http://www.geekpage.jp/programming/linux-network/tcp-2.php
どこか修正する点があるのでしょうか?
0408デフォルトの名無しさん
2008/06/23(月) 23:02:12間のルータがマルチキャストルータで、かつルータの先のルータが
別ネットワークからのマルチキャストに応答し、かつ、別ネットワークから
のUPnPのTCP接続に正しく応答するなら可能なんじゃね?
0409デフォルトの名無しさん
2008/06/23(月) 23:45:55ありがと
ちょっと作ってみる
0410デフォルトの名無しさん
2008/06/24(火) 10:03:12同じLAN内で動かなかったのなら何が問題があると思われ
0411デフォルトの名無しさん
2008/06/24(火) 12:08:13単に「うまく動かない」では状況がわからない
何かエラーメッセージが出るとか、こういう動作を期待したのに実際はこうだったとか、もっと詳しく
0412デフォルトの名無しさん
2008/06/24(火) 14:11:03うちの環境だと動いたよ。
firewallがブロックしてんじゃねーの?
0413デフォルトの名無しさん
2008/06/29(日) 00:12:03アプリケーションがネットワークにアクセスしようとしたときに
とりあえずブロックしてから確認ダイアログ出すけど、
アプリケーション開始したときに確認ダイアログ出せない?
ひたすらリトライするしかない?
Visual Studio 2008
言語はC#かC++でplz
0414デフォルトの名無しさん
2008/06/29(日) 00:18:320415デフォルトの名無しさん
2008/06/29(日) 02:08:520416デフォルトの名無しさん
2008/06/29(日) 02:19:380417デフォルトの名無しさん
2008/06/29(日) 02:51:47馬鹿か
0418デフォルトの名無しさん
2008/06/29(日) 11:16:14num = recv(dst, buf, buf_size, 0);
if(numrcv == 0 || numrcv == -1){
status = close(dst);
break;
}
printf("received: %s\n", buf);
}
ネット上から拾ったプログラムです。
簡易tcpサーバーとしてAccept後、文字列受信をしているんだが、なぜ
受信→if判定でbreak→出力
という形なのか教えてください。
自分の中では
受信→出力→if判定でbreak
が普通だと思うのだが。
0419デフォルトの名無しさん
2008/06/29(日) 11:46:07Windowsなら、socket使わなければWSAGetLastErrorでとれる値は変わらないだろうけど、
UNIXだったらerrnoが変わっちゃうかも知れない。
(errno == EINTRだったらやり直すとか)
それに、毎回受信したデータを処理してしまうにしても、0はともかく-1は困らない?
numrcv = recv(s, buf, len, 0);
memcpy(dst, buf, numrcv);
みたいなのとか。
出力するにしても、どれだけ出力すればいいのか分かるの?
bufが全部'\0'で初期化されてるなら、文字列として出力する分には平気だと思うけど。
0420デフォルトの名無しさん
2008/06/29(日) 12:01:11>受信→出力→if判定でbreak
その場合、受信に失敗してたら、なにが出力されるんだ?
0421418
2008/06/29(日) 12:03:36言われてみればエラーチェックと考えられますね。
ありがとうございました。
■ このスレッドは過去ログ倉庫に格納されています