2016-04-05 9 views
1

select()write_fdsを設定する際に何か間違っている必要があります。現在、sendData()を呼び出すと、初めてバッファから117バイト(すべて)が送信されます。それからすぐにそれはバッファに送信するデータがなくても、もう一度呼び出され、sendData()は永遠に呼び出し続けます。Cでselect()とwrite_fdsを設定する

私がここで間違っているのは何ですか?

int readData(int j){ 
    return recv(j, buf , nbytes , 0); 
} 
int sendData(int j){ 
    unsigned v = fcntl(j, F_GETFL, 0); 
    fcntl(j, F_SETFL, v | O_NONBLOCK); 

    return send(j, buf, nbytes, 0); 
} 

fd_set master; 
fd_set read_fds; 
fd_set write_fds; 
int fdmax;  
... 
FD_ZERO(&master); 
FD_SET(socket, &master); 
fdmax = socket; 

for(;;){ 
    FD_ZERO(&read_fds); 
    FD_ZERO(&write_fds); 

    read_fds = master; 
    write_fds = master; 
    if(select(fdmax+1, &read_fds, &write_fds, NULL, NULL) == -1){ 
     exit(4); 
    } 
    for(i = 0; i <= fdmax; i++){ 
     if(FD_ISSET(i, &read_fds)){ 
      if(i == socket){ 
       // handle new connections 
       addrlen = sizeof remoteaddr; 
       newfd = accept(socket, (struct sockaddr *)&addr, &addrlen); 
       FD_SET(newfd, &master); 
       if(newfd > fdmax) fdmax = newfd; 
      }else{ 
       // we got some data from a client 
       readData(i); 
      } 
     } else if(FD_ISSET(i, &write_fds)){ 
      if(i != socket){ 
       // send data when notified 
       sendData(i); 
      } 
     }  
    } 
} 
+2

ええと、呼びたくないコードを停止してください。 –

+0

'master'から同じfdセットを上書きする直前に、' FD_ZERO'を呼び出すことに意味がありません。 – Barmar

+0

@Barmarこれを指摘してくれてありがとう。 –

答えて

2

あなたは(つまり、write_fdsがチェックされているものです)より多くのデータを送信するためにネットワークスタック内のスペースがあるときに通知する選択を求めています。 117バイトしか書いていないので、十分なスペースがあるので、すぐに戻り、より多くのデータを書き込むように指示します。

送信するデータがもうないので、ファイルディスクリプタをwrite_fdsから削除してください。 sendの呼び出しが短い書き込み(すべてのデータを書き込めない)またはEWOULDBLOCK(非ブロックモードに設定されていると仮定)を返した場合にのみ、write_fdsに追加します。

これはコードに大きな問題を引き起こします。戻り値をチェックせずにsend/recvを呼び出すので、実際に送受信されたデータの量はわかりません。

+0

ありがとうございます。私は 'send/recv'の戻り値と' -1'と 'EWOULDBLOCK'を返すかどうかを調べています。 fdを 'write_fds'から、また短い書込みや' EWOULDBLOCK'から削除するべきだと私が理解しているか分かりません。 'if(sent <= 0)FD_SET(i、&master);を実行することを意味しますか? else FD_CLR(i、&master); '? –

+0

@PeteDarrow:上記のコードでは、 'master'は' read_fds'と 'write_fds'の和集合です - 一般的にはそれらを別々に追跡して管理したいと思っています。だから、あなたが望むものは 'If(sent <試み_to_send)FD_SET(i、&master_write); else FD_CLR(i、&master_write); ' –

0

ほとんどの場合、ソケットは書き込み可能です。もしあなたが以前にsend()からのEAGAIN/EWOULDBLOCKを持っていたなら、書き込みを再試行して成功させたときにその作業をやめるべきです。

関連する問題