[Tự học lập trình C/C++] Xử lý tín hiệu (Signal Handling)

Tín hiệu (Signal) là các ngắt (interrupt) được phân phối tới một tiến trình xử lý bởi hệ điều hành mà có thể kết thúc một chương trình. Bạn có thể tạo các ngắt bằng việc nhấn CTRL+C trên hệ thống UNIX, LINUX, Mac OS hoặc Windows.
Có các signal mà không thể bị bắt bởi chương trình, nhưng cũng có signal mà bạn có thể bắt trong chương trình của bạn, và có thể thực hiện các hành động thích hợp dựa trên signal đó. Những signal này được định nghĩa trong Header file của C++ là <csignal>.
SignalMiêu tả
SIGABRTSự kết thúc bất thường của chương trình, ví dụ một lời gọi tới abort
SIGFPEMột hoạt động số học không đúng, ví dụ như chia cho số 0 hoặc một hoạt động làm tràn luồng (overflow)
SIGILLSự phát hiện một chỉ lệnh không hợp lệ
SIGINTNhận một tín hiệu tương tác
SIGSEGVMột truy cập không hợp lệ tới storage
SIGTERMMột yêu cầu kết thúc được gửi tới chương trình

Hàm signal() trong C++

Thư viện xử lý tín hiệu trong C++ cung cấp hàm signal để bẫy các sự kiện không được mong đợi. Dưới đây là cú pháp của hàm signal() trong C++:
void (*signal (int sig, void (*func)(int)))(int); 
Hàm này nhận hai tham số: tham số đầu tiên là một số nguyên mà biểu diễn số hiệu tín hiệu (signal number) và tham số thứ hai là một con trỏ tới hàm xử lý tín hiệu.
Bây giờ, viết một chương trình C++ đơn giản để bắt tín hiệu SIGINT bởi sử dụng hàmsignal() trong C++. Bất cứ tín hiệu nào bạn muốn bắt trong chương trình, bạn phải ghi tín hiệu đó bởi sử dụng hàm signal và liên kết nó với một Signal Handler. Bạn xét ví dụ:
#include <iostream>
#include <csignal>

using namespace std;

void signalHandler( int tinhieuso )
{
    cout << "Tin hieu ngung chuong trinh (" << tinhieuso << ") da duoc nhan.\n";

      
    // ket thuc chuong trinh  

   exit(tinhieuso);  

}

int main ()
{
    // dang ky tin hieu SIGINT va Signal Handler  
    signal(SIGINT, signalHandler);  

    while(1){
       cout << "Going to sleep...." << endl;
       
    }

    return 0;
}
Biên dịch và chạy chương trình C++ trên sẽ cho kết quả sau:
Xử lý tín hiệu trong C++
Bây giờ, nhấn CTRL+C để ngắt chương trình và bạn sẽ thấy rằng chương trình sẽ bắt tín hiệu này và sẽ in cái gì đó như sau:
Going to sleep....
Going to sleep....
Going to sleep....
Tin hieu ngung chuong trinh (2) da duoc nhan.

Hàm raise() trong C++

Bạn có thể tạo các tín hiệu bởi hàm raise() trong C++, mà nhận một số integer biểu diễn signal number như một tham số và có cú pháp như sau:
int raise (signal sig);
Ở đây, sig là signal number để gửi bất kỳ loại tín hiệu nào: SIGINT, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM, SIGHUP. Dưới đây là ví dụ tạo một tín hiệu nội tại bởi sử dụng hàm raise() trong C++, như sau:
#include <iostream>
#include <csignal>

using namespace std;

void signalHandler( int tinhieuso )
{
    cout << "Tin hieu ngung chuong trinh (" << tinhieuso << ") da duoc nhan.\n";

    
    // ket thuc chuong trinh

   exit(tinhieuso);  

}

int main ()
{
    int i = 0;
    // dang ky tin hieu SIGINT va Signal Handler  
    signal(SIGINT, signalHandler);  

    while(++i){
       cout << "Going to sleep ... (Met Wa roi!!!)" << endl;
       if( i == 7 ){
          raise( SIGINT);
       }
    
    }

    return 0;
}
Biên dịch và chạy chương trình C++ trên sẽ cho kết quả sau:
Xử lý tín hiệu trong C++

[Lập trình C/C++] Đa luồng (Multithread)

Đa luồng (Multithreading) là một form chuyên dụng của đa nhiệm (multitasking) và một đa nhiệm là tính năng cho phép máy tính của bạn chạy hai hoặc nhiều chương trình đồng thời. Nói chung, có hai kiểu đa nhiệm là: process-based và thread-based tương ứng: dựa trên tiến trình và dựa trên luồng.
Đa nhiệm dựa trên tiến trình xử lý việc thực thi đồng thời của các chương trình. Đa nhiệm dựa trên luồng xử lý việc thực thi đồng thời các phần của cùng một chương trình.
Một chương trình đa luồng chứa hai hoặc nhiều phần mà có thể chạy đồng thời. Mỗi phần của chương trình đó được gọi là một thread, và mỗi thread định nghĩa một path riêng biệt của sự thực thi.
C++ không chứa bất kỳ hỗ trợ có sẵn nào cho các ứng dụng đa luồng. Thay vào đó, nó dựa hoàn toàn vào Hệ điều hành để cung cấp tính năng này.
Chương này giả sử bạn đang làm việc trên Hệ điều hành Linux và chúng tôi đang chuẩn bị viết chương trình đa luồng trong C++ bởi sử dụng POSIX. POSIX Threads hoặc Pthreads cung cấp API mà có sẵn trên nhiều hệ thống như FreeBSD, NetBSD, GNU/Linux, Mac OS X và Solaris.

Tạo Thread trong C++

Đây là chương trình chúng ta sử dụng để tạo một POSIX thread:
#include <pthread.h>
pthread_create (thread, attr, start_routine, arg) 
Ở đây, pthread_create tạo một thread mới và làm nó có thể thực thi. Chương trình này có thể được gọi bất cứ thời điểm nào ở bất cứ đâu trong code của bạn. Dưới đây là miêu tả các tham số:
Tham sốMiêu tả
threadMột định danh duy nhất cho thread mới được trả về bởi chương trình con
attrMột thuộc tính mà có thể được sử dụng để thiết lập các thuộc tính của thread. Bạn có thể xác định một đối tượng thuộc tính thread, hoặc NULL cho các giá trị mặc định
start_routineChương trình C++ mà thread này sẽ thực thi một khi nó được tạo
argMột tham số đơn mà có thể được truyền tới start_routine. Nó phải được truyền bởi tham chiếu dạng một con trỏ của kiểu void. NULL có thể được sử dụng nếu không có tham số nào được truyền
Số thread tối đa có thể được tạo bởi một tiến trình là phụ thuộc vào trình triển khai (Implementation). Một khi được tạo, các thread là ngang hàng, và có thể tạo các thread khác. Không có sự phụ thuộc giữa các thread trong C++.

Kết thúc Thread trong C++

Chương trình sau được sử dụng để kết thúc một POSIX thread trong C++:
#include <pthread.h>
pthread_exit (status) 
Ở đây pthread_exit được sử dụng để kết thúc một thread. Chương trình pthread_exit() được gọi sau khi một thread đã hoàn thành công việc của nó và không cần thiết phải tồn tại nữa.
Nếu main() kết thúc trước các thread nó đã tạo, và kết thúc chương trình pthread_create(), thì các thread khác sẽ tiếp tục thực thi. Nếu không thì, chúng sẽ tự động được kết thúc khi main() hoàn thành.

Ví dụ

Ví dụ đơn giản sau tạo 5 thread với chương trình pthread_create(). Mỗi thread in một thông báo "Hello World!", và sau đó kết thúc với một lời gọi tới pthread_exit() trong C++:
#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define SO_THREAD     4

void *InLoiChao(void *threadid)
{
   
   cout << "Hello World! Thread ID la " << threadid << endl;
   pthread_exit(NULL);
}

int main ()
{
   pthread_t threads[SO_THREAD];
   int rc;
   int i;
   for( i=0; i < SO_THREAD; i++ ){
      cout << "\nmain() : dang tao thread! " << i << endl;
      rc = pthread_create(&threads[i], NULL, 
                          InLoiChao, (int *)i);
      if (rc){
         cout << "\nError: Khong the tao thread!" << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}
Nếu bạn đang sử dụng command promt để biên dịch chương trình, thì bạn sử dụng thư viện –lpthread như sau:
$gcc test.cpp -lpthread
Nếu không, biên dịch và chạy chương trình C++ trên sẽ cho kết quả sau:
Multithread trong C++

Truyền tham số tới Thread trong C++

Ví dụ này minh họa cách truyền nhiều tham số thông qua một cấu trúc. Bạn có thể truyền bất kỳ kiểu dữ liệu nào trong một Thread callback, bởi vì nó trỏ tới void như được giải thích trong ví dụ sau:
#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define SO_THREAD     5

struct du_lieu{
   int  id;
   char *thongdiep;
};

void *InLoiChao(void *thamso)
{
   struct du_lieu *data;

   data = (struct du_lieu *) thamso;

   cout << "\nThread ID la: " << data->id ;
   cout << "\nThong diep: " << data->thongdiep << endl;

   pthread_exit(NULL);
}

int main ()
{
   pthread_t threads[SO_THREAD];
   struct du_lieu td[SO_THREAD];
   int rc;
   int i;

   for( i=0; i < SO_THREAD; i++ ){
      cout <<"\nmain() : dang tao thread! " << i << endl;
      td[i].id = i;
      td[i].thongdiep = "\nDay la thong diep";
      rc = pthread_create(&threads[i], NULL,
                          InLoiChao, (void *)&td[i]);
      if (rc){
         cout << "\nError: Khong the tao thread! " << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}
Biên dịch và chạy chương trình C++ trên sẽ cho kết quả sau:
Multithread trong C++

Kết hợp và Tháo gỡ các Thread trong C++

Hai cú pháp sau được sử dụng để kết hợp (joining) hoặc tháo gỡ (detaching) các Thread trong C++:
pthread_join (threadid, status) 
pthread_detach (threadid) 
Chương trình con pthread_join() đóng khối thread đang gọi tới khi threadid kết thúc. Khi một thread được tạo, một trong các thuộc tính định nghĩa nó là joinable hoặc detached. Chỉ các thread được tạo với dạng joinable có thể được kết hợp. Nếu một thread được tạo với dạng detached, nó không bao giờ được kết hợp.
Ví dụ sau minh họa cách đợi cho các thread kết thúc bởi sử dụng chương trình kết hợp Pthread trong C++:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define SO_THREAD     5

void *wait(void *tid)
{
   int i;
  

   sleep(1);
   cout << "\nDang tam dung mot Thread " << endl;
   cout << "\nThread voi ID la : " << tid << "  ... dang thoat! " << endl;
   pthread_exit(NULL);
}

int main ()
{
   int rc;
   int i;
   pthread_t threads[SO_THREAD];
   pthread_attr_t attr;
   void *status;

   // khoi tao va thiet lap mot thread co the ket hop
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

   for( i=0; i < SO_THREAD; i++ ){
      cout << "\nmain() : dang tao thread! " << i << endl;
      rc = pthread_create(&threads[i], NULL, wait, (void *)i );
      if (rc){
         cout << "\nError: Khong the tao thread! " << rc << endl;
         exit(-1);
      }
   }

   // giai phong thuoc tinh va doi thread khac
   pthread_attr_destroy(&attr);
   for( i=0; i < SO_THREAD; i++ ){
      rc = pthread_join(threads[i], &status);
      if (rc){
         cout << "\nError: khong the ket hop! " << rc << endl;
         exit(-1);
      }
      cout << "\nMain: ket huc thread id :" << i ;
      cout << "  va thoat voi trang thai:" << status << endl;
   }

   cout << "\nMain: thoat chuong trinh!" << endl;
   pthread_exit(NULL);
}
Biên dịch và chạy chương trình C++ trên sẽ cho kết quả sau:
Multithread trong C++

[Tự học lập trình C/C++] Lập trình Web trong C++

CGI là gì?

  • Common Gateway Interface hoặc CGI là một tập hợp các chuẩn mà định nghĩa cách thông tin được trao đổi giữa Web Server và một Custom Script.
  • CGI Specification hiện tại được duy trì bởi NCSA và NCSA định nghĩa CGI như sau: Common Gateway Interface hoặc CGI là một chuẩn cho các chương trình kết nối dị mạng ngoại vi (external gateway programs) tới Interface với thông tin từ Server như HTTP Server.
  • Phiên bản hiện tại là CGI/1.1 và CGI/1.2 đang trong quá trình phát triển.

Web Browsing

Để hiểu khái niệm về CGI, chúng ta xem những gì xảy ra khi chúng ta nhấn vào một hyperlink để tới một Webpage hoặc URL cụ thể.
  • Trình duyệt của bạn liên hệ HTTP Web Server và yêu cầu một URL, ví dụ: filename.
  • Web Server sẽ parse URL đó và sẽ tìm kiếm filename. Nếu nó tìm thấy file đã yêu cầu, thì Web Server gửi file đó trở lại trình duyệt, nếu không thì, nó gửi một thông báo lỗi chỉ rằng bạn đã yêu cầu một wrong file.
  • Trình duyệt Web nhận phản hồi từ Web Server và hiển thị file đã nhận được hoặc thông báo lỗi dựa trên phản hồi đã nhận.
Tuy nhiên, nó là có thể để thiết lập HTTP Server theo cách mà bất cứ khi nào một file trong một thư mục cụ thể được yêu cầu, thì file đó không được gửi trở lại; thay cho việc nó được thực thi như là một chương trình và output được tạo từ chương trình đã gửi tới trình duyệt để hiển thị.
Common Gateway Interface hoặc CGI là một giao thức chuẩn cho các ứng dụng (được gọi là CGI program hoặc CGI script) khả năng tương tác với Web Server và với Client. Những CGI program này có thể được viết bằng Python, PERL, Shell, C hoặc C++ …

Sơ đồ cấu trúc CGI

Dưới đây là sơ đồ một cấu trúc đơn giản của CGI:
Cấu trúc CGI

Cấu hình Web Server

Trước khi bạn tiếp tục với lập trình CGI, đảm bảo rằng Web Server của bạn hỗ trợ CGI và nó được định cấu hình để xử lý CGI Program. Tất cả CGI program để được thực thi bởi HTTP Server được giữ trong một thư mục được định cấu hình trước. Thư mục này được gọi là CGI directory, và theo qui ước, nó được đặt tên là /var/www/cgi-bin. Theo qui ước, CGI file có đuôi là .cgi, vì thế chúng là có thể thực thi trong C++.
Theo mặc định, Apache Web Server được định cấu hình để chạy CGI Program trong /var/www/cgi-bin. Nếu bạn muốn xác định bất kỳ thư mục khác để chạy CGI script của bạn, thì bạn phải sửa đổi khu vực sau trong httpd.conf file:
<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options ExecCGI
   Order allow,deny
   Allow from all
</Directory>
 
<Directory "/var/www/cgi-bin">
Options All
</Directory>

Chương trình CGI đầu tiên

Xét nội dung chương trình C++ sau:
#include <iostream>
using namespace std;
 
int main ()
{
    
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Hello World - Chuong trinh CGI dau tien</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<h2>Hello World! Day la Chuong trinh CGI dau tien cua toi</h2>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}
Biên dịch code trên và đặt tên là cplusplus.cgi. File này được giữ trong thư mục /var/www/cgi-bin và nó có nội dung như sau. Trước khi chạy CGI Program của bạn, bảo đảm rằng bạn đã chuyển chế độ của file bởi sử dụng lệnh chmod 755 cplusplus.cgi trên UNIX để làm file có thể thực thi. Kết quả là:

Hello World! Day la Chuong trinh CGI dau tien cua toi

Chương trình C++ trên là một chương trình đơn giản mà đang ghi output trên STDOUT file, ví dụ: màn hình. Có một tính năng quan trọng có sẵn để dòng đầu tiên được in là Content-type:text/html\r\n\r\n. Dòng này gửi trở lại trình duyệt và xác định kiểu nội dung để được hiển thị trên màn hình trình duyệt. Bây giờ bạn đã hiểu khái niệm cơ bản về CGI và bạn có thể viết nhiều CGI Program phức tạp bởi sử dụng C++. Một CGI Program trong C++ có thể tương tác với bất kỳ hệ thống ngoại vi khác như RDBMS, để trao đổi thông tin.

HTTP Header

Dòng Content-type:text/html\r\n\r\n là một phần của HTTP Header, mà được gửi tới trình duyệt. Tất cả HTTP Header có form sau:
HTTP Field Name: Noi dung truong
 
Vi du:
Content-type: text/html\r\n\r\n
Dưới đây là một số HTTP Header quan trọng, mà bạn sẽ sử dụng thường xuyên trong Lập trình CGI.
HeaderMiêu tả
Content-type:Một chuỗi MIME định nghĩa định dạng của file đang được trả về. Ví dụ: Content-type:text/html
Expires: DateNgày thông tin hết hiệu lực. Nó nên được sử dụng bởi trình duyệt để quyết định khi nào một trang cần được refresh. Một chuỗi date hợp lệ nên trong định dạng 01 Jan 1998 12:00:00 GMT
Location: URLURL mà nên được trả về thay cho URL đã yêu cầu. Bạn có thể sử dụng trường này để redirect một yêu cầu tới bất kỳ file nào
Last-modified: DateNgày sửa đổi cuối cùng của nguồn
Content-length: NĐộ dài, bằng byte, của dữ liệu đang được trả về. Trình duyệt sử dụng giá trị này để báo cáo lượng thời gian download ước lượng cho một file
Set-Cookie: StringThiết lập cookie đã truyền thông qua string

Biến môi trường của CGI

Tất cả CGI Program sẽ có truy cập tới các biến môi trường sau đây. Những biến này đóng vai trò quan trọng trong khi viết bất kỳ CGI Program nào:
Tên biếnMiêu tả
CONTENT_TYPEKiểu dữ liệu của nội dung. Được sử dụng khi Client gửi nội dung đính kèm tới Server. Ví dụ: file upload
CONTENT_LENGTHĐộ dài của thông tin truy vấn. Nó chỉ có sẵn cho các yêu cầu POST
HTTP_COOKIETrả về các cookie đã thiết lập trong form là cặp key/value
HTTP_USER_AGENTTrường request-header là User-Agent chứa thông tin về User Agent bắt đầu yêu cầu đó. Nó là tên của trình duyệt web
PATH_INFOLà path cho CGI script
QUERY_STRINGThông tin mã hóa URL được gửi với phương thức GET
REMOTE_ADDRĐịa chỉ IP của host từ xa tạo yêu cầu đó. Nó có thể là hữu ích cho mục đích log hoặc authentication
REMOTE_HOSTTên đầy đủ của host tạo yêu cầu đó. Nếu thông tin này không có sẵn, thì REMOTE_ADDR có thể được sử dụng để lấy địa chỉ IP
REQUEST_METHODPhương thức được sử dụng để tạo yêu cầu. Các phương thức phổ biến là GET và POST
SCRIPT_FILENAMEPath đầy đủ tới CGI script
SCRIPT_NAMETên của CGI script
SERVER_NAMEHostname hoặc địa chỉ IP của Server
SERVER_SOFTWARETên và phiên bản của phần mềm mà Server đang chạy
Sau đây là chương trình CGI nhỏ để liệt kê tất cả biến CGI.
#include <iostream>
#include <stdlib.h>
using namespace std;

const string ENV[ 24 ] = {                 
        "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",   
        "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",             
        "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION",         
        "HTTP_HOST", "HTTP_USER_AGENT", "PATH",            
        "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",      
        "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME",
        "SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN",      
        "SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL",     
        "SERVER_SIGNATURE","SERVER_SOFTWARE" };   

int main ()
{
    
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cac bien CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";

   for ( int i = 0; i < 24; i++ )
   {
       cout << "<tr><td>" << ENV[ i ] << "</td><td>";
       // lay gia tri cua cac bien
       char *value = getenv( ENV[ i ].c_str() );  
       if ( value != 0 ){
         cout << value;                                 
       }else{
         cout << "Bien moi truong nay khong ton tai.";
       }
       cout << "</td></tr>\n";
   }
   cout << "</table><\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Thư viện CGI trong C++

Với các ví dụ thực tế, bạn sẽ cần thực hiện nhiều hoạt động bởi CGI Program của bạn. Có một thư viện CGI được viết cho chương trình C++, mà bạn có thể tải về từ:ftp://ftp.gnu.org/gnu/cgicc/ và theo các bước sau để cài đặt thư viện này:
$tar xzf cgicc-X.X.X.tar.gz 
$cd cgicc-X.X.X/ 
$./configure --prefix=/usr 
$make
$make install
Bạn có thể kiểm tra Documentation có sẵn tại: C++ CGI Lib Documentation.

Phương thức POST và GET

Bạn gặp một số tình huống khi bạn cần truyền một số thông tin từ trình duyệt tới Web Server và sau cùng tới CGI Program của bạn. Hai phương thức được sử dụng thường xuyên nhất bởi trình duyệt để truyền các thông tin này tới Web Server là Phương thức GET và Phương thức POST.

Truyền thông tin bởi sử dụng phương thức GET

Phương thức GET gửi thông tin người dùng đã mã hóa được phụ thêm tới trang yêu cầu. Trang và thông tin đã mã hóa được phân biệt bởi ký tự ? như sau:
http://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2
Phương thức GET là phương thức mặc định để truyền thông tin từ trình duyệt tới Web Server và nó tạo ra một chuỗi dài xuất hiện trong Location:box của trình duyệt. Đừng bao giờ sử dụng phương thức GET nến bạn có mật khẩu hoặc thông tin nhạy cảm khác để truyền tới Server. Phương thức GET có giới hạn kích cỡ và bạn có thể truyền 1024 ký tự trong một Request String.
Khi sử dụng phương thức GET, thông tin được truyền bởi trường HTTP Header là QUERY_STRING và sẽ là có thể truy cập trong CGI Program thông qua biến môi trường QUERY_STRING.
Bạn có thể truyền thông tin bằng việc nối chuỗi các cặp key/value cùng với bất kỳ URL hoặc bạn có thể sử dụng các thẻ HTML <FORM> để truyền thông tin bởi sử dụng phương thức GET.

Ví dụ URL đơn giản sử dụng phương thức GET

Đây là một URL đơn giản sẽ truyền hai value tới chương trình hello_get.py bởi sử dụng phương thức GET.
/cgi-bin/cpp_get.cgi?first_name=CHINH&last_name=TRAN
Dưới đây là chương trình để tạo CGI Program là cpp_get.cgi để xử lý input được cung cấp bởi trình duyệt web. Chúng ta đang sử dụng thư viện CGI trong C++, để làm cho nó dễ dàng hơn để truy cập thông tin đã truyền:
#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>  

using namespace std;
using namespace cgicc;

int main ()
{
   Cgicc formData;
   
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Su dung cac phuong thuc GET va POST</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("first_name");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "First name: " << **fi << endl;  
   }else{
      cout << "Khong co du lieu nao duoc nhap vao cho first name" << endl;  
   }
   cout << "<br/>\n";
   fi = formData.getElement("last_name");  
   if( !fi->isEmpty() &&fi != (*formData).end()) {  
      cout << "Last name: " << **fi << endl;  
   }else{
      cout << "Khong co du lieu nao duoc nhap vao cho last name" << endl;  
   }
   cout << "<br/>\n";

   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}
Bây giờ, biên dịch chương trình trên như sau:
$g++ -o cpp_get.cgi cpp_get.cpp -lcgicc
Tạo cpp_get.cgi và đặt nó trong thư mục CGI của bạn.

Ví dụ về FORM bởi sử dụng phương thức GET

Ví dụ đơn giản sau sẽ truyền hai value bởi sử dụng HTML FORM và nút submit. Chúng ta đang sử dụng cùng CGI Program là cpp_get.cgi để xử lý input này.
<form action="/cgi-bin/cpp_get.cgi" method="get">
First Name: <input type="text" name="first_name">  <br />
 
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
Đây là output thực sự của form trên. Bạn có thể nhập First và Last Name và sau đó click nút Submit để xem kết quả:

First Name: 
Last Name:  

Truyền thông tin bởi sử dụng phương thức POST

Một phương thức chung đáng tin cậy hơn để truyền thông tin tới một CGI Program là phương thức POST. Nó đóng gói thông tin theo cách giống phương thức GET, nhưng thay vì gửi nó ở dạng một chuỗi văn bản sau một dấu ? trong URL, nó gửi ở dạng một thông báo riêng biệt. Thông báo này tới CGI Script trong form đầu vào chuẩn.
Cùng sử dụng CGI Program là cpp_get.cgi để xử lý phương thức POST. Chúng ta sử dụng cùng ví dụ như trên, mà sẽ truyền hai value bởi sử dụng HTML FORM và nút Submit, nhưng lần này với phương thức POST như sau:
<form action="/cgi-bin/cpp_get.cgi" method="post">
First Name: <input type="text" name="first_name"><br />
Last Name: <input type="text" name="last_name" />
 
<input type="submit" value="Submit" />
</form>
Đây là output thực sự của form trên. Bạn nhập First và Last Name và sau đó nhấn nút Submit để xem kết quả:

First Name: 
Last Name:  

Truyền Checkbox Data tới CGI Program

Checkbox được sử dụng khi có nhiều hơn một tùy chọn là cần thiết để được lựa chọn:
HTML code sau là ví dụ cho một form với hai checkbox:
<form action="/cgi-bin/cpp_checkbox.cgi" 
         method="POST" 
         target="_blank">
<input type="checkbox" name="maths" value="on" /> Maths
<input type="checkbox" name="physics" value="on" /> Physics
<input type="submit" value="Select Subject" />
</form>
Kết quả của code này là form sau:
 Maths  Physics 
Chương trình C++ sau sẽ tạo cpp_checkbox.cgi để xử lý input được cung cấp bởi trình duyệt thông qua nút checkbox:
#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main ()
{
   Cgicc formData;
   bool maths_flag, physics_flag;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Checkbox Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   maths_flag = formData.queryCheckbox("maths");
   if( maths_flag ) {  
      cout << "Maths Flag: ON " << endl;  
   }else{
      cout << "Maths Flag: OFF " << endl;  
   }
   cout << "<br/>\n";

   physics_flag = formData.queryCheckbox("physics");
   if( physics_flag ) {  
      cout << "Physics Flag: ON " << endl;  
   }else{
      cout << "Physics Flag: OFF " << endl;  
   }
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Truyền Radiobutton Data tới CGI Program

Radio Button được sử dụng khi chỉ có một tùy chọn là cần thiết để lựa chọn.
HTML code sau là ví dụ cho form với hai radio button:
<form action="/cgi-bin/cpp_radiobutton.cgi" 
         method="post" 
         target="_blank">
<input type="radio" name="subject" value="maths" 
                                    checked="checked"/> Maths 
<input type="radio" name="subject" value="physics" /> Physics
<input type="submit" value="Select Subject" />
</form>
Kết quả của code trên là form sau:
 Maths  Physics 
Chương trình C++ sau sẽ tạo cpp_radiobutton.cgi để xử lý input được cung cấp bởi trình duyệt web thông qua các radio button:
#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main ()
{
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Radio Button Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("subject");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Radio box selected: " << **fi << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Truyền Text Area Data tới CGI Program

Phần tử TEXTAREA được sử dụng khi văn bản nhiều dòng phải được truyền tới CGI Program.
HTML code sau là ví dụ cho một form với một TEXTAREA box:
<form action="/cgi-bin/cpp_textarea.cgi" 
         method="post" 
         target="_blank">
<textarea name="textcontent" cols="40" rows="4">
Type your text here...
</textarea>
<input type="submit" value="Submit" />
</form>
Đây là kết quả của form trên:
Chương trình C++ sau sẽ tạo cpp_textarea.cgi để xử lý input được cung cấp bởi trình duyệt web thông qua text area:
#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main ()
{
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Text Area Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("textcontent");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Text Content: " << **fi << endl;  
   }else{
      cout << "No text entered" << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Truyền DropDown Box Data tới CGI Program

DropDown Box được sử dụng khi có nhiều tùy chọn có sẵn, nhưng chỉ có một hoặc hai sẽ được chọn:
HTML code sau là ví dụ cho một form với một Dropdown box:
<form action="/cgi-bin/cpp_dropdown.cgi" 
                       method="post" target="_blank">
<select name="dropdown">
<option value="Maths" selected>Maths</option>
<option value="Physics">Physics</option>
</select>
<input type="submit" value="Submit"/>
</form>
Kết quả của code trên là form sau:

 
Chương trình C++ sau sẽ tạo cpp_dropdown.cgi để xử lý input được cung cấp bởi trình duyệt web thông qua dropdown box:
#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h> 

using namespace std;
using namespace cgicc;

int main ()
{
   Cgicc formData;
  
   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Drop Down Box Data to CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("dropdown");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "Value Selected: " << **fi << endl;  
   }
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Sử dụng Cookie trong CGI

HTTP Protocol là một giao thức Stateless. Nhưng với một Website thương mại, nó là cần thiết để duy trình thông tin session giữa các trang khác nhau. Ví dụ, một tiến trình đăng ký của người sử dụng có thể kết thúc sau khi hoàn thành qua nhiều trang. Nhưng cách để duy trì thông tin session của người dùng khi họ duyệt qua nhiều trang là như thế nào.
Trong nhiều tình huống, sử dụng Cookie là phương thức hiệu quả nhất để ghi nhớ và theo dấu việc đặt hàng, mua hàng, hàng hóa ưa thích, …

Cách nó làm việc

Server của bạn gửi một số dữ liệu tới trình duyệt khách truy cập trong form của một Cookie. Trình duyệt có thể chấp nhận Cookie này. Nếu nó chấp nhận, nó được lưu giữ ở dạng một bản ghi thuần văn bản trên Hard drive của khách truy cập. Bây giờ, khi khác truy cập tới trang khác trên site của bạn, Cookie này là có sẵn để thu hồi. Khi được thu hồi, Server của bạn biết/nhớ những gì được lưu giữ:
Cookie là một bản ghi dữ liệu thuần văn bản của 5 trường biến:
  • Expires : Ngày mà Cookie sẽ hết hạn. Nếu để trống, Cookie sẽ hết hạn khi khách truy cập thoát khỏi trình duyệt.
  • Domain : Tên miền của site của bạn
  • Path : Path tới thư mục hoặc Webpage mà thiết lập Cookie đó. Nó có thể là trống nếu bạn muốn thu nhận Cookie từ bất kỳ thư mục hoặc trang nào.
  • Secure : Nếu trường này chứa từ “secure”, thì Cookie chỉ có thể được thu hồi với một Secure Server. Nếu trường này để trống, sẽ không tồn tại hạn chế nào.
  • Name=Value : Cookie được thiết lập và thu hồi trong form các cặp key/value.

Thiết lập Cookie

Rất dễ dàng để gửi Cookie tới trình duyệt. Những Cookie này được gửi cùng với HTTP Header ở trước trường Content-type. Giả sử bạn muốn thiết lập UserID và Password ở dạng Cookie. Thì thiết lập Cookie sẽ được thực hiện như sau:
#include <iostream>
using namespace std;

int main ()
{
 
   cout << "Set-Cookie:UserID=XYZ;\r\n";
   cout << "Set-Cookie:Password=XYZ123;\r\n";
   cout << "Set-Cookie:Domain=www.tutorialspoint.com;\r\n";
   cout << "Set-Cookie:Path=/perl;\n";
   cout << "Content-type:text/html\r\n\r\n";

   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cookies in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   cout << "Setting cookies" << endl;  
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}
Từ ví dụ này, bạn phải hiểu cách thiết lập Cookie. Chúng ta sử dụng HTTP Header là Set-Cookie để thiết lập các Cookie.
Ở đây, nó là tùy ý để thiết lập các thuộc tính của Cookie như Expires, Domain, và Path. Bạn nhớ rằng, Cookie được thiết lập trước khi gửi dòng sau: "Content-type:text/html\r\n\r\n.
Biên dịch chương trình trên để tạo setcookies.cgi. Nó sẽ thiết lập 4 Cookie tại máy tính của bạn.

Thu hồi Cookie

Việc thu hồi tất cả Cookie đã thiết lập là khá dễ dàng. Cookie được lưu giữ trong biến môi trường CGI là HTTP_COOKIE và chúng sẽ có form sau:
key1=value1;key2=value2;key3=value3....
Dưới đây là ví dụ về cách thu hồi các Cookie:
#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
   Cgicc cgi;
   const_cookie_iterator cci;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>Cookies in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";
   
   // get environment variables
   const CgiEnvironment& env = cgi.getEnvironment();

   for( cci = env.getCookieList().begin();
        cci != env.getCookieList().end(); 
        ++cci )
   {
      cout << "<tr><td>" << cci->getName() << "</td><td>";
      cout << cci->getValue();                                 
      cout << "</td></tr>\n";
   }
   cout << "</table><\n";
  
   cout << "<br/>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}
Bây giờ, biên dịch chương trình trên để tạo getcookies.cgi, và thử lấy danh sách tất cả Cookie có sẵn tại máy tính của bạn.
Nó sẽ cho một danh sách gồm 4 Cookie đã được thiết lập ở phần trước và tất cả Cookie khác được thiết lập tại máy tính của bạn:
UserID XYZ 
Password XYZ123 
Domain www.tutorialspoint.com 
Path /perl 

Ví dụ về File Upload

Để tải một file lên, HTML code phải có thuộc tính enctype được thiết lập là multipart/form-data. Thẻ input với kiểu file này sẽ tạo một nút “Browse”.
<html>
<body>
   <form enctype="multipart/form-data" 
            action="/cgi-bin/cpp_uploadfile.cgi" 
            method="post">
   <p>File: <input type="file" name="userfile" /></p>
   <p><input type="submit" value="Upload" /></p>
   </form>
</body>
</html>
Kết quả của code trên sẽ là form sau:
File: 
Ghi chú: Ví dụ trên đã bị vô hiệu hóa để tránh người dùng Upload file lên Server của chúng tôi. Nhưng bạn có thể thử code trên với Server của bạn.
Đây là chương trình cpp_uploadfile.cpp để xử lý upload file:
#include <iostream>
#include <vector>  
#include <string>  
#include <stdio.h>  
#include <stdlib.h> 

#include <cgicc/CgiDefs.h> 
#include <cgicc/Cgicc.h> 
#include <cgicc/HTTPHTMLHeader.h> 
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
   Cgicc cgi;

   cout << "Content-type:text/html\r\n\r\n";
   cout << "<html>\n";
   cout << "<head>\n";
   cout << "<title>File Upload in CGI</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   // get list of files to be uploaded
   const_file_iterator file = cgi.getFile("userfile");
   if(file != cgi.getFiles().end()) {
      // send data type at cout.
      cout << HTTPContentHeader(file->getDataType());
      // write content at cout.
      file->writeToStream(cout);
   }
   cout << "<File uploaded successfully>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}
Ví dụ trên đang ghi nội dung tại cout stream, nhưng bạn có thể mở file stream của bạn và giữ nội dung của upload file trong một file tại vị trí mong muốn.

Bài đăng phổ biến

Bài viết mới nhất

Tin học cơ bản - Nền tảng của mọi kỹ năng

Mọi thông tin trên blog đều được giữ bản quyền bởi Tin học cơ bản. Các bạn nếu muốn lấy thông tin từ blog vui lòng ghi rõ nguồn Tinhoccoban.net

TIN HỌC CƠ BẢN