[Linuxネットワークプログラミング]ループサーバの実現

5343 ワード

一、循環サーバーの定義
ループサーバは、1つの時点で1つのリクエストのみを処理するサーバ実装形態を記述し、単一スレッド内にループ制御を設定することによって、複数のクライアントリクエストに対する逐一応答を実現し、このようなサーバの設計、プログラミング、デバッグ、および修正は、容易に実現されることが多い.このタイプのサーバは、サイクル実行されるサーバが所望の負荷に対して十分な反応速度を提供するためによく使用される.循環サーバーにはUDP循環サーバーとTCP循環サーバーの2種類があります.
二、UDP循環サーバーUDP循環サーバーの実現方法:UDPサーバーはソケットから一つのクライアントの要求を読み取るたびに、要求を処理して、結果をクライアントに返す.
このようなサーバでは、UDPは非接続であるため、常にサービス側を占有できるクライアントは1つもないので、UDPループサーバはクライアントごとの要求を常に満たすことができる.
参照コードは次のとおりです.
#include   
#include   
#include   
#include   
#include   
#include   
#include   
  
#define PORT 2222  
#define MAX_SIZE 512  
  
int main()  
{  
    int sockfd;  
    int len = sizeof(struct sockaddr);  
  
    char buf[MAX_SIZE];  
    char buffer[MAX_SIZE];  
  
    struct sockaddr_in serv_addr;  
      
    //     ,IPV4/UDP  
    sockfd = socket(AF_INET,SOCK_DGRAM,0);  
    if(sockfd < 0)  
    {  
        printf("create socket error!
"); exit(1); } // bzero(&serv_addr,sizeof(struct sockaddr_in)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); serv_addr.sin_addr.s_addr = inet_addr("192.168.1.132"); // if(bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr)) < 0) { printf("bind error!
"); exit(1); } // while(1) { // if(recvfrom(sockfd,buf,MAX_SIZE,0,(struct sockaddr*)&serv_addr,&len) < 0) { printf("recv error!
"); exit(1); } printf("recv is: %s
",buf); printf("write some text:"); scanf("%s",buffer); // if(sendto(sockfd,buffer,MAX_SIZE,0,(struct sockaddr*)&serv_addr,len) < 0) { printf("send error!
"); fprintf(stderr,"send error:%s
",strerror(errno)); exit(1); } } close(sockfd); // return 0; }

三、TCP循環サーバー:TCPサーバーは一つのクライアントの接続を受け入れて、それから処理して、このクライアントのすべての要求を完成した後、接続を切る.
TCPは接続向けであるため、TCPループサーバは、同じ時点で1つのクライアントの要求のみを一度に処理することができる.このクライアントのすべてのリクエストが満たされた後でのみ、サーバは後続のリクエストを継続できます.これにより、あるクライアントがサーバを占有して放さない場合、他のクライアントは動作しないため、TCPサーバは一般的に循環サーバモデルを使用することは少ない.
参照コードは次のとおりです.
#include    
#include    
#include    
#include    
#include    
#include    
#include    
#include    
  
#define portnumber 2222 //       
  
int main(int argc, char *argv[])   
{   
    int sockfd,new_fd;   
    struct sockaddr_in server_addr;   
    struct sockaddr_in client_addr;   
    int sin_size;   
    int nbytes;  
    char buffer[1024];  
  
    /*         sockfd    */   
    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) // IPV4  ;TCP    
    {   
        fprintf(stderr,"Socket error:%s
\a",strerror(errno)); exit(1); } /* sockaddr */ bzero(&server_addr,sizeof(struct sockaddr_in)); // , 0 server_addr.sin_family=AF_INET; // IPV4 server_addr.sin_addr.s_addr=htonl(INADDR_ANY); // ( long long ) ,INADDR_ANY : IP //server_addr.sin_addr.s_addr=inet_addr("192.168.1.132"); // IP,inet_addr ip ip server_addr.sin_port=htons(portnumber); // ( short short ) /* sockfd IP */ if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) { fprintf(stderr,"Bind error:%s
\a",strerror(errno)); exit(1); } /* */ if(listen(sockfd,5)==-1) { fprintf(stderr,"Listen error:%s
\a",strerror(errno)); exit(1); } while(1) { /* , */ sin_size=sizeof(struct sockaddr_in); if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1) { fprintf(stderr,"Accept error:%s
\a",strerror(errno)); exit(1); } fprintf(stderr,"Server get connection from %s
",inet_ntoa(client_addr.sin_addr)); // . if((nbytes=read(new_fd,buffer,1024))==-1) { fprintf(stderr,"Read Error:%s
",strerror(errno)); exit(1); } buffer[nbytes]='\0'; printf("Server received %s
",buffer); /* */ close(new_fd); /* */ } /* */ close(sockfd); exit(0); }

四、循環サーバーの欠点
サーバがクライアントリクエストを処理している間に別のリクエストが来ると、システムは新しいリクエストをキューに入れます.2番目のリクエストは、最初のリクエストが処理されるまで待たなければなりません.これにより、クライアントリクエストが頻繁すぎる、すなわち、クライアントリクエストが多すぎると、サーバのリクエストチームがますます長くなり、応答時間が長くなります.