ZBLOG

#include #include #include #include #include #include #include #define PORT 443 // HTTPS 默认端口 void init_openssl() { SSL_load_error_strings(); OpenSS...

要将现有的基于阻塞的HTTPS服务器代码改为事件驱动的方式,您可以使用epoll来处理多个连接而不需要为每个连接都创建一个新的线程或进程。以下是如何修改代码以实现此目的:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/epoll.h>

#define PORT 443 // HTTPS 默认端口
#define MAX_EVENTS 10

void init_openssl() {
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
}

void cleanup_openssl() {
    EVP_cleanup();
}

SSL_CTX *create_context() {
    const SSL_METHOD *method;
    SSL_CTX *ctx;

    method = TLS_server_method(); // 使用更安全的 TLS 服务端方法
    ctx = SSL_CTX_new(method);
    
    if (!ctx) {
        perror("Unable to create SSL context");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    return ctx;
}

void configure_context(SSL_CTX *ctx) {
    // 加载证书和私钥,这里需要指定你的证书和私钥文件路径
    if (SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM) <= 0 ||
        SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
}

int main() {
    int sockfd;
    
    struct sockaddr_in addr;

    init_openssl();
    
    SSL_CTX *ctx = create_context();
    
    configure_context(ctx);

   // 创建 Socket
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
   
   if (sockfd == -1) {
       perror("socket");
       exit(EXIT_FAILURE);
   }

   // 设置服务器地址
   memset(&addr, 0, sizeof(addr));
   addr.sin_family = AF_INET;
   addr.sin_addr.s_addr = INADDR_ANY; 
   addr.sin_port = htons(PORT);

   // 绑定 Socket
   if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
       perror("bind failed");
       close(sockfd);
       exit(EXIT_FAILURE);
   }

   // 开始监听连接
   if (listen(sockfd, SOMAXCONN) != 0) {
       perror("listen failed");
       close(sockfd);
       exit(EXIT_FAILURE);
   }

   printf("Listening on port %d...\n", PORT);

   int epoll_fd = epoll_create1(0); // 创建epoll实例
   struct epoll_event event;

   event.events = EPOLLIN; // 对可读事件感兴趣
   event.data.fd = sockfd; 
   
   epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &event); // 添加监听套接字到epoll中

   while (1) {
       struct epoll_event events[MAX_EVENTS];
       
       int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); // 等待事件发生

       for (int i = 0; i < nfds; ++i) {
           if (events[i].data.fd == sockfd) { 
               struct sockaddr_in client_addr;
               socklen_t client_len = sizeof(client_addr);

               int client_sock = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);

               if (client_sock < 0) {
                   perror("accept failed");
                   continue;
               }

               event.events = EPOLLIN | EPOLLET; // 边缘触发模式
               event.data.fd = client_sock;

               epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_sock, &event); // 添加客户端套接字到epoll中

           } else { 
               int client_sock = events[i].data.fd;
               
               SSL *ssl = SSL_new(ctx); 
               
               if (!ssl || SSL_set_fd(ssl, client_sock) == 0 || SSL_accept(ssl)<=0){
                   ERR_print_errors_fp(stderr); 
                   close(client_sock); 
                   continue;  
               }
               
               char buf[1024];
               memset(buf, 0,sizeof(buf));

                int bytes_read=SSL_read(ssl ,buf,sizeof(buf)); 

                if(bytes_read>0)
                    printf("Received: %s\n", buf);

                const char* response="HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello World!";
                SSL_write(ssl,response,sizeof(response)); 

                // 清理工作
                SSL_shutdown(ssl); 
                SSL_free(ssl);  
                close(client_sock);  
           }
       }
      
      
       
     
     
     
      
      
       
   
   

     
    
   
   
   

   

  
   
    
    

    
    
     
     

     
       

         
           
            
          
           
           
             
              
                
                 
                  
                   
                   
                    



                   


                       
                   
                   
                    
                     
                      

                     
                      
  
       
       
       
       
       
       

      

       

       

     }


   

  

  
   
  


   

  
  
  
  

 
  




   
  

 
    
   
    

 
  
 
 
  

    

 

   

  
    
     
     

     
    
     

    
    





     


     


 

   
    
      

        
        


         
         
         




        
        

    


    
     

  
    
 
    
    


     
        

        
          
             
    
  
  
  
  
  
  
  


  


     

    

     

  

    
    

  


    

  

  
  
    
     

   
    
   
    
    



      
         
        



        
         
          
         
           
             
            
             
            
             
           


           

  
               
               
                

                 



                
                    
                    
                        
                    
                
                 


                 

 
 




              
              
                  
                       
                
                
                     
                
                 

 

                      
                     
 
                  
                          
                          
        
                         
        
                         
                         


                           
                           
                             
                    
                     
                 
                  
                 
                 
                   
                  
                    
                    
                    

 
                     
                     
   
                  
                 


                 



                 
            

             
            

















          
          
  
 
  
 

  

  
  

 
  
 
 
 
 
 








}


      

    



   

 
  

   

    

 
  

  
 
  

 
 
 
 



// 清理工作







cleanup_openssl();

return EXIT_SUCCESS;  
}

更改说明:

  1. 创建epoll实例:在主函数中,我们通过调用 epoll_create1 创建了一个 epoll 实例。
  2. 添加监听套接字到 epoll:我们用 epoll_ctl 将服务器监听套接字添加到 epoll 的监视列表中,以便能检测到新的连接请求。
  3. 使用边缘触发模式 (EPOLLET):为了提高性能,我们对客户端套接字设置了边缘触发(Edge Triggered)模式。这样可以减少系统调用次数。
  4. 读取和写入:在事件循环内处理读写操作,并做相应错误处理。

注意事项:

  • 确保您的 OpenSSL 配置、证书路径以及密钥文件正确。
  • 此代码示例并没有全面处理所有错误情况,应根据实际需求进行完善。


    内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=5904

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?