- PR -

ソケットプログラミング UDP TCP bind()について

投稿者投稿内容
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2007-11-03 08:15
引用:

ごめzさんの書き込み (2007-11-03 01:42) より:
UDPの場合は不可能なんですかね?


だから、標準的なバークレイソケットの範囲で使う限りでは不可能。

WindowsXPのnetstatはプロセスIDまで表示できることから判るように、OSに依存したかたちでインターフェースが用意されている可能性はある。

でも先に言ったように自分のIPアドレスとかポート番号は意識しないほうが良い。ブロードバンドルータ(NATサーバ)が介在していれば、自分の認識しているポート番号と
サーバーが認識しているポート番号が一致しない場合もある。一台で複数のIPアドレスを保有している場合には、どちらのIPを使っているのかと言うことが問題になったりもする。クライアントが自分のIPアドレスとポート番号をきちんと扱うのは以外にメンドクサイ仕様なんですよ。
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2007-11-03 08:36
引用:
ごめzさんの書き込み (2007-11-03 01:42) より:
引用:
未記入さんの書き込み (2007-11-01 10:11) より:
connect() したあとなら、getsockname() で分かるんじゃないかな。。


UDPの場合は不可能なんですかね?


UDPの場合でも、クライアント側なら socket→connect→send ( sendto ) の流れになるでしょうから、getsockname でいけそうですけど。
テストプログラムを一本書いてみれば分かるのでは…。
※UDPの場合でも、connect, bind どちらかは使うことになるので、その時点で自分のポート番号は決定されますよね。
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2007-11-03 09:31
引用:
甕星さんの書き込み (2007-11-03 08:15) より:
だから、標準的なバークレイソケットの範囲で使う限りでは不可能。


getsockname って、非標準なんでしたっけ…。

通信するときに、クライアント側が自分のポート番号を意識する必要がない ( OSに決めてもらう ) のは確かですが、デバッグや解析用に、何番ポートを使っていたかログに残すくらいはあっても良いと思いますけど。
※ごめzさんの意図が何処にあるかは知りませんが
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2007-11-03 09:56
引用:
自分の書き込み (2007-11-03 08:36) より:
テストプログラムを一本書いてみれば分かるのでは…。


適当に書いてみました。
サーバ側が udps.c、クライアント側が udpc.c、それぞれ何処からパケットが投げられたか、自分(クライアント)の使ったアドレス・ポートが何処かを出力します。
サーバは、127.0.0.1:12345 を bind します。(クライアントはそこに向かって投げます)
・実行結果
コード:
$ ./udps &
[1] 3770
$ ./udpc
send from: 127.0.0.1:59507  ← クライアント側出力
recv from: 127.0.0.1:59507  ← サーバ側出力(クライアントと一致)


・共通ファイル udp.h
コード:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SVR_UDP_PORT 12345
#define SET_SVR_ADDR(saddr) \
  do { \
    saddr.sin_family = AF_INET; \
    saddr.sin_port = htons(SVR_UDP_PORT); \
    saddr.sin_addr.s_addr = htonl(0x7f000001); \
  } while (0)


・udpc.c
コード:
#include "udp.h"

int main(void)
{
  int s;
  char dummy[] = "abc";
  struct sockaddr_in svraddr, clientaddr;
  socklen_t clientlen = sizeof(clientaddr);

  s = socket(PF_INET, SOCK_DGRAM, 0);
  SET_SVR_ADDR(svraddr);
  connect(s, (const struct sockaddr *)&svraddr, sizeof(svraddr));
  getsockname(s, (struct sockaddr *)&clientaddr, &clientlen);
  printf("send from: %s:%d\\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
  send(s, dummy, sizeof(dummy), 0);
  return 0;
}


・udps.c
コード:
#include "udp.h"

int main(void)
{
  int s;
  char trash[256];
  struct sockaddr_in svraddr, clientaddr;
  socklen_t clientlen = sizeof(clientaddr);

  s = socket(PF_INET, SOCK_DGRAM, 0);
  SET_SVR_ADDR(svraddr);
  bind(s, (const struct sockaddr *)&svraddr, sizeof(svraddr));
  for (;;)
  {
    recvfrom(s, trash, sizeof(trash), 0, (struct sockaddr *)&clientaddr, &clientlen);
    printf("recv from: %s:%d\\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
  }
  return 0;
}

ごめz
会議室デビュー日: 2007/10/31
投稿数: 15
投稿日時: 2007-11-03 21:58
引用:

angelさんの書き込み (2007-11-03 09:56) より:
引用:
自分の書き込み (2007-11-03 08:36) より:
テストプログラムを一本書いてみれば分かるのでは…。


適当に書いてみました。
サーバ側が udps.c、クライアント側が udpc.c、それぞれ何処からパケットが投げられたか、自分(クライアント)の使ったアドレス・ポートが何処かを出力します。
サーバは、127.0.0.1:12345 を bind します。(クライアントはそこに向かって投げます)



大変わかりやすい説明ありがとうございます。
connect()するとわかるのですね。
逆を言うとconnect()しないとわからないのですか。

UDP Socket生成→sendto()
だけでポート番号がわかれば最適だったのですが,
UDPの性質上無理がありましたね。
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2007-11-04 00:00
引用:
ごめzさんの書き込み (2007-11-03 21:58) より:
UDP Socket生成→sendto()
だけでポート番号がわかれば最適だったのですが,


分からないかどうかまでは調べていませんし、私は知りません。
※sendto した後のソケットに対して getsockname やればいいだけかもしれませんが。

ただ、クライアント側であれば、connect してから send すれば良いだけなので、socket→いきなりsendto という流れは、私は無視しています。
それに、幾らUDPクライアントとは言え、ただ送るだけだとピンポンダッシュに過ぎませんので、送信したデータグラムに対する応答の受信も考えるものだと思っています。
それであれば、socket→bind→sendto→recvfrom もしくは socket→connect→send→recv のどちらかの流れになるでしょうから、自動的に socket→いきなりsendto は考慮する必要がなくなりますよね。( socket→sendto→recvfrom でも良いのなら話は別ですが、それは知りません )
blunder
ベテラン
会議室デビュー日: 2003/09/11
投稿数: 65
投稿日時: 2007-11-05 11:22
引用:

大変わかりやすい説明ありがとうございます。
connect()するとわかるのですね。
逆を言うとconnect()しないとわからないのですか。

UDP Socket生成→sendto()
だけでポート番号がわかれば最適だったのですが,
UDPの性質上無理がありましたね。



であれば、
1.socketを開く
2.ポート番号0でbindする
3.getsocknameでポート番号を得る
4.sendtoでデータを送る
がいいと思いますが、いかがでしょう。

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