- PR -

acceptのエラー

投稿者投稿内容
kuri2
会議室デビュー日: 2005/01/28
投稿数: 10
投稿日時: 2005-01-28 14:25
はじめまして。
ソケットを用いて通信を行っています。
サーバー側で


ソケット作成
bind
listenを行った後

struct sockaddr *Addr;  
socklen_t * len;

printf("ACCEPT START! SOCKET\n");

// Accept Start
int s_down;
   if((s_down = accept(s, Addr, len))<0){
printf("->ERR! SOCKET=%d ACCEPT IN Accept()",s);
return -1;

}
printf("ACCEPT OK! SOCKET %d\n",s_down);

のようにacceptを行っていますが、
クライアント側がコネクトした後、(クライアント側はコネクト成功)
その後、サーバー側は何も返ってこずaccept OKにもエラーにもならず、
待ったままです。
クライアント側はコネクト成功したためsendを実行、接続できずに
タイムアウトになっています。
その後、しばらくしてから、クライアント側からコネクトしてきたら、
accept OK となり、送受信(send,recv)を行います。
ソケットを用いた通信を作成するのが初めてで、解析の仕方がわかりません。
よろしくお願いします。
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2005-01-28 15:35
サーバープログラム稼動時のリソースの負荷は?
後、「サーバー側は何も返ってこずaccept OKにもエラーにもならず、待ったまま」の時の

netstat の状態は?

LISTEN のまんま?
ぽんす
ぬし
会議室デビュー日: 2003/05/21
投稿数: 1023
投稿日時: 2005-01-28 18:34
え〜と、ソケットプログラミングでは有名な話なんですが、
(Unix系OSのサーバだと)サーバのプロセスがaccept(2)を発行する前に
クライアントのconnect(2)は成功します。
# カーネルが気を利かせて勝手に先を進めてしまうため。
いまの場合、クライアントのコネクトは成功していても、サーバ側の
*プロセスとしては* accept() は発行されていない状態でしょう。

じゃあ、いつまでも accept()が行われないのはどういうわけだ、
というのはまた別の話ですが、意図せずそうなったのなら
それはプログラムの問題のわけで。

かなり省略されててよく分かりませんが、みたところ
accept(2) の引数のポインタに実体が用意されていないような...
kuri2
会議室デビュー日: 2005/01/28
投稿数: 10
投稿日時: 2005-01-31 11:34
有難うございます。
すみません。
説明不足で。
えーと、めったにおきません。
装置に組み込んでいるため、キーボードとかもなく
print文だけが頼りです。
デバッグ中にはおきたことがなく、装置に組み込んでもめったにおきません。
もう少し詳細に書くと
acceptの引数はそれぞれ別の関数を作成して取得しています。
第1引数は
SOCKET Socket()
{
SOCKET s;
if ((s = socket(AF_INET, SOCK_STREAM,0)) < 0 ) {
return RET_NG;
}
return s;
}

第2引数は
int GetHostName(char *hostname,sockaddr_in *dst_Addr,short port)
{
struct hostent *mhost;
/*IPアドレスを取得*/
if((mhost = gethostbyname(hostname)) == NULL) {
fprintf(stderr,"bad hostname!\n");
return RET_NG;
}

/*接続先情報をソケット型構造体にセット*/
bzero((char *)dst_Addr,sizeof(*dst_Addr));
dst_Addr->sin_family = AF_INET;
dst_Addr->sin_port = htons(port); // 固定値9876
bcopy(mhost->h_addr, (char*)&dst_Addr->sin_addr, mhost->h_length);
return RET_OK;
}

// SOCKET =int
int Accept(SOCKET s,struct sockaddr *Addr,socklen_t * len){
int s_down;

***このacceptの前後でprintしていますが
  ここではwait 中 と表示されている。
  ずーと待ったまま。 クライアンと側はconnect Ok となり
  送信してくるがタイムアウトとなっている。その後 connectされると
  OKとなりmainに戻る
  

if((s_down = accept(s, Addr, len))<0){
printf("->ERR! SOCKET=%d ACCEPT IN Accept()\n",s);
return RET_NG;

}
return s_down;

}

int Bind(SOCKET s,struct sockaddr *Addr,int size)
{
if (bind(s, Addr, size) == -1) {
printf("->ERR! BIND IN Bind()\n");
return RET_NG;
    return RET_OK;
}


***全体のながれです。エラー処理は省いています。
main(){
struct sockaddr_in srcAddr;
struct sockaddr_in dstAddr;
char hostname[256];
SOCKET r_socket;

GetHostName(hostname,&srcAddr,IN_PORT); //自分自身
r_socket=Socket();
Bind(r_socket, (struct sockaddr *)&srcAddr, sizeof(srcAddr));
Listen(r_socket);

socklen_t dstAddr_len=sizeof(dstAddr);
s_rdown = Accept(r_socket, (struct sockaddr *)&dstAddr,&dstAddr_len);
Recv();// 省略

}
まだまだ未熟ですのでacceptが発行されているかどうかどのように
調べるのでしょうか。
プログラムにもまだまだ問題があるとは思いますが。
ぽんす
ぬし
会議室デビュー日: 2003/05/21
投稿数: 1023
投稿日時: 2005-01-31 21:12
う〜ん、イマイチ状況がわからないのですが...
> s_rdown = Accept(r_socket, (struct sockaddr *)&dstAddr,&dstAddr_len);
ということなので、前回私が書いたポインタの件は的外れでしたね。

サーバのプロセスを起動して初回の接続がうまく行かない、という
ことかと思っていたのですが、
> えーと、めったにおきません。
というところからするとそうではなくて、ほとんどの場合はうまく
行ってるんだけど、たまにダメなことがある、ということでしょうか?
で、ダメな場合でも、もう一度接続するとそっちはうまく行く、と?

症状からすると、レースコンディションかなあ、という気がします。
select(2) でポーリングしておいて、accept(2) する、とか
そんな流れじゃあないかと思いますが、accept() しようとした
ときにはすでにその対象がなくなっていたのでブロックし続けている、
という状況であるようにみえます。
他のスレッドが accept() してしまったか、accept() する前に
なんらかのエラーで閉じられてしまったか...

なので、もう一度接続するとブロックが解消される、ということで。

とりあえずの対症療法としては accept() に制限時間を設けて
タイムアウトするようにする、という手もありそうですが、
そうすることに意味があるかどうかはケースバイケースですね。
kuri2
会議室デビュー日: 2005/01/28
投稿数: 10
投稿日時: 2005-02-02 09:57
どうも有難うございます。
まだまだ勉強不足で、文章もわかりにくくて申し訳ありません。

サーバのプロセスを起動して初回の接続がうまく行かない、という
ことかと思っていたのですが、
> えーと、めったにおきません。
というところからするとそうではなくて、ほとんどの場合はうまく
行ってるんだけど、たまにダメなことがある、ということでしょうか?
で、ダメな場合でも、もう一度接続するとそっちはうまく行く、と?

そうですね。
サーバー(こちら)はacceptした状態でずっと待っている。
クライアント側はconnectして、送信しくる。そして、タイムアウト
closeする。その後、しばらくしてからクライアントがconnectしてきたときは
先ほどサーバー側がaccept待ちになっているのでそのままOKとなり
送受信が可能です。

こういったことが起きる可能性があるのならば、
起きたときの対処をしなければならないので、、、、
selectで時間監視、そのままクライアントが再度connectするまで
待っている、、(あまり、進歩がないような、、)
ブロックされているかどうか見る方法はあるのでしょうか?
ぽんす
ぬし
会議室デビュー日: 2003/05/21
投稿数: 1023
投稿日時: 2005-02-02 21:21
えーと、用語をあまりご存知ないようで、私がたいそうなことを言ってる
ようにみえたかもしれませんが、実はたいしたことは言ってないのです
それはともかく。

「ブロックしている」というのは「システムコールを発行したらそのまま
返ってこない」ということです。すなわち、いま見えている症状のことです。
ブロックしないようにするにはソケットをノンブロッキングにするとか
alarm でも仕込んでタイムアウトするようにするとかの手があります。
が、いまの場合、クライアントがずっと待ちになっているのも「まずい」
ことなのではないかと思いますが、この方法ではそれに対しては無力です。

バグだと仮定すると、サーバがどう接続を受け付けているかという点に
問題がありそうな気がします。どうやってクライアントが接続してきた
ことを知るのか?あるいは知らずにずっと待っているのか?サーバは
ただひとつだけのスレッドで構成されているのか?などなど。

にゃんですが、どうも奇妙な症状であるようにみえます。
クライアントのIPアドレスが他のマシンとぶつかっていたら
そんな症状が出そうな気がするのですが... そういうことは
ないですか?
kuri2
会議室デビュー日: 2005/01/28
投稿数: 10
投稿日時: 2005-02-04 08:55
有難うございます。
システムに関しては本当に初心者で勉強不足です。
サーバー側といっても本当のサーバーではなく送受信の機能からみると
サーバーの機能ということで1対1で送受信しています。
スレッドは1つです。クライアント側はタイムアウトでクローズして
終了しています。
IPアドレスはサーバー、クライアントとも固定にしています。
社内で割り当てられている使用可能のIPでぶつかってはいないはずです。
あと、スレッドですが、こちら側がクライアント機能として
相手に送信しているスレッドがあります。この場合、ポートは別のポートを
使っています。ただ、そのスレッドは動いていないときでも起きています。
ネットワークは無線LANを使用しています。

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