Linux網絡編程——tcp并發服務器(多進程)

一、tcp并發服務器概述
一個好的服務器,一般都是并發服務器(同一時刻可以響應多個客戶端的請求)。并發服務器設計技術一般有:多進程服務器、多線程服務器、I/O復用服務器等。

二、多進程并發服務器
Linux 環境下多進程的應用很多,其中最主要的就是網絡/客戶服務器。多進程服務器是當客戶有請求時,服務器用一個子進程來處理客戶請求。父進程繼續等待其它客戶的請求。這種方法的優點是當客戶有請求時,服務器能及時處理客戶,特別是在客戶服務器交互系統中。對于一個 TCP 服務器,客戶與服務器的連接可能并不馬上關閉,可能會等到客戶提交某些數據后再關閉,這段時間服務器端的進程會阻塞,所以這時操作系統可能調度其它客戶服務進程,這比起循環服務器大大提高了服務性能。
發達
tcp多進程并發服務器
TCP 并發服務器的思想是每一個客戶機的請求并不由服務器直接處理,而是由服務器創建一個子進程來處理。

tcp多進程并發服務器參考代碼:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>                         
#include <unistd.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>      
  
/************************************************************************ 
函數名稱:   void main(int argc, char *argv[]) 
函數功能:   主函數,用進程建立一個TCP Echo Server 
函數參數:   無 
函數返回:   無 
************************************************************************/  
int main(int argc, char *argv[])  
{  
    unsigned short port = 8080;     // 本地端口   
  
    //1.創建tcp套接字  
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);     
    if(sockfd < 0)  
    {  
        perror("socket");  
        exit(-1);  
    }  
      
    //配置本地網絡信息  
    struct sockaddr_in my_addr;  
    bzero(&my_addr, sizeof(my_addr));     // 清空     
    my_addr.sin_family = AF_INET;         // IPv4  
    my_addr.sin_port   = htons(port);     // 端口  
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip  
      
    //2.綁定  
    int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));  
    if( err_log != 0)  
    {  
        perror("binding");  
        close(sockfd);        
        exit(-1);  
    }  
      
    //3.監聽,套接字變被動  
    err_log = listen(sockfd, 10);   
    if(err_log != 0)  
    {  
        perror("listen");  
        close(sockfd);        
        exit(-1);  
    }  
      
    while(1) //主進程 循環等待客戶端的連接  
    {  
          
        char cli_ip[INET_ADDRSTRLEN] = {0};  
        struct sockaddr_in client_addr;  
        socklen_t cliaddr_len = sizeof(client_addr);  
          
        // 取出客戶端已完成的連接  
        int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);  
        if(connfd < 0)  
        {  
            perror("accept");  
            close(sockfd);  
            exit(-1);  
        }  
          
        pid_t pid = fork();  
        if(pid < 0){  
            perror("fork");  
            _exit(-1);  
        }else if(0 == pid){ //子進程 接收客戶端的信息,并發還給客戶端  
            /*關閉不需要的套接字可節省系統資源, 
              同時可避免父子進程共享這些套接字 
              可能帶來的不可預計的后果 
            */  
            close(sockfd);   // 關閉監聽套接字,這個套接字是從父進程繼承過來  
          
            char recv_buf[1024] = {0};  
            int recv_len = 0;  
              
            // 打印客戶端的 ip 和端口  
            memset(cli_ip, 0, sizeof(cli_ip)); // 清空  
            inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);  
            printf("----------------------------------------------\n");  
            printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));  
              
            // 接收數據  
            while( (recv_len = recv(connfd, recv_buf, sizeof(recv_buf), 0)) > 0 )  
            {  
                printf("recv_buf: %s\n", recv_buf); // 打印數據  
                send(connfd, recv_buf, recv_len, 0); // 給客戶端回數據  
            }  
              
            printf("client_port %d closed!\n", ntohs(client_addr.sin_port));  
            close(connfd);    //關閉已連接套接字  
            exit(0);  
              
        }  
        else if(pid > 0){    // 父進程  
            close(connfd);    //關閉已連接套接字  
        }  
    }  
      
    close(sockfd);  
      
    return 0;  
}  

運行結果:


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容