2013-10-24 8 views
5

このサーバーは、クライアントとの新しい接続を待ち受けて既存の接続に同時に書き込むことができるようにする必要があります。非同期ノンブロッキングI/O私はpoll()を使用するように言われましたが、単にソケットプログラミングを理解しようと過度​​の時間を費やした後も、poll()関数の実装方法はまだ分かりません。TCPサーバーの読み取り/書き込みでpoll()を実装する

int sockfd; 

int main(int argc, char *argv[]) 
{ 
int newsockfd, portno; 
socklen_t clilen; 
char buffer[256];  
struct sockaddr_in serv_addr, cli_addr; 
int n;    

if (argc < 2) {   
    fprintf(stderr,"ERROR, no port provided\n"); 
    exit(1); 
} 

sockfd = socket(AF_INET, SOCK_STREAM, 0);  
if (sockfd < 0)      
    error("ERROR opening socket");   

bzero((char *) &serv_addr, sizeof(serv_addr));  

portno = atoi(argv[1]);    
serv_addr.sin_family = AF_INET;   
serv_addr.sin_addr.s_addr = INADDR_ANY;  
serv_addr.sin_port = htons(portno);  

if (bind(sockfd, (struct sockaddr *) &serv_addr, 
      sizeof(serv_addr)) < 0) 
      error("ERROR on binding");   
listen(sockfd,5);     

clilen = sizeof(cli_addr);  

while(1){   
    newsockfd = accept(sockfd, 
       (struct sockaddr *) &cli_addr, 
       &clilen);    
    if (newsockfd < 0)     
      error("ERROR on accept"); 

    // READ READ READ READ READ READ READ READ READ READ READ READ READ READ READ READ 
    bzero(buffer,256); 
    n = read(newsockfd,buffer,255);  


    if (n < 0) error("ERROR reading from socket"); 
    printf("Here is the message: %s\n",buffer); 

    // WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE 
    n = write(newsockfd,"I got your message",18); 
    if (n < 0) error("ERROR writing to socket"); 
    close(newsockfd); 
} 

return 0; 

}

私の理解では、私はこのような何か構築する必要があるということです

// Set up array of file descriptors for polling 
struct pollfd ufds[2]; 
ufds[0].fd = sockfd;  
ufds[0].events = POLLIN; 

ufds[1].fd = newsockfd; 
ufds[1].events = POLLOUT; 

と使用の世論調査(ufds、2,2000)を、ループ内でsockfdやnewsockfdが何らかのアクティビティを持っているかどうかをチェックします。その場合は、適切な読み取りまたは書き込みを使用します。もし誰かが私にいくつかの指針を与えることができたら、私は非常に感謝します。

+1

「選択」について読んでいますか? – NiRR

答えて

3

カーネルはstruct pollfdアレイのreventsフィールドで発生したイベントを入力します。マニュアルページから

フィールドにreventsは、実際に起こったイベントがカーネルにより満たされた出力パラメータ、です。 reventsで返されるビットには、イベントで指定されたもの、またはPOLLERR、POLLHUP、またはPOLLNVALのいずれかの値を含めることができます。 (これらの3ビットは、イベントの分野でも意味がなく、対応する条件が真の場合にreventsに設定されます。)

あなたが受け入れた接続のためのイベント通知をしたい場合は、どちらかの予備空間にする必要があり接続ごとにstruct pollfdアレイを進めたり、サイズを変更したりしてください。

リスニングソケットを区別する方法が必要です。配列のインデックス0に格納することができます。

int i, n; 

n = poll(ufds, num_fds_in_array, timeout_value); 

/* errors or timeout? */ 
if (n < 1) 
    ; 

for (i = 0; i < num_fds_in_array; i++) { 
    /* were there any events for this socket? */ 
    if (!ufds[i].revents) 
     continue; 

    /* is it our listening socket? */ 
    if (!i) { 
     if (ufds[0].revents & POLLIN) 
      /* call accept() and add the new socket to ufds */ 
     else 
      /* error */ 

     continue; 
    } 

    /* is there incoming data on the socket? */ 
    if (ufds[i].revents & POLLIN) 
     /* call recv() on the socket and decide what to do from there */ 
} 

POLLOUTフラグがソケット上の送信データは、発信者をブロックしない場合に通知するために使用されます。

ノンブロッキングI/Oの場合、より強力なAPIを使用します。なぜなら、信頼性の高い簿記が必要になるからです。次の段落を参照してください。

pollを使用すると、残念ながら、接続ごとの補助データに状態を保存する余地はありません。お使いのプラットフォームに応じて選択肢が用意されています。 g。 Linuxの場合はepoll、* BSDの場合はkqueue、Windowsの場合はいくつかのオプションがあります。コンテキストデータにpollを使用する場合は、ファイル記述子または配列インデックスを使用して検索できるデータ構造を使用する必要があります。

+0

このコードをOPコードにどのように適用できるかを示していただければ幸いです。私は正確にブロックするread()コマンドを持っているのとまったく同じ問題がありますが、接続タイムアウトが必要です。私はたくさんのことを試みましたが、うまくいきません。私はあなたのコードを理解していない... ufdsは何ですか?それはnewsockfdですか? –

関連する問題