cari
Rumahpembangunan bahagian belakangC++Menggunakan API dalam C: panduan praktikal untuk pembangun moden

Consuming APIs in C: a practical guide for modern developers

Hari ini, menggunakan API web ialah amalan biasa untuk bertukar-tukar data antara aplikasi. Tutorial tentang penggunaan API dalam bahasa seperti JavaScript, Python atau PHP adalah banyak, tetapi C—sering dikaitkan dengan pengaturcaraan peringkat sistem—jarang dipertimbangkan untuk tujuan ini. Walau bagaimanapun, C mampu sepenuhnya mengendalikan permintaan API, menjadikannya pilihan yang berdaya maju untuk senario seperti sistem Point of Sale (PoS), peranti IoT atau aplikasi terbenam, di mana C sudah digunakan untuk kecekapan dan kawalan peringkat rendahnya.

Artikel ini meneroka cara menggunakan API dalam C, memanfaatkan perpustakaan libcurl. Pada akhirnya, anda akan memahami cara untuk mengambil dan memproses data daripada API menggunakan C dan sebab pendekatan ini relevan walaupun dalam pembangunan moden.

Mengapa menggunakan C untuk menggunakan API?

Walaupun bahasa peringkat lebih tinggi mendominasi pembangunan web, C masih menjadi pilihan praktikal untuk menggunakan API dalam kes penggunaan tertentu:

  • Prestasi: C menyediakan prestasi tinggi dan overhed minimum, menjadikannya sesuai untuk persekitaran yang terhad sumber seperti peranti IoT.
  • Kawalan: pengurusan memori langsung membolehkan pengoptimuman diperhalusi, terutamanya untuk sistem terbenam.
  • Saling kendali: Penggunaan meluas C bermakna ia berintegrasi dengan baik dengan operasi peringkat sistem, seperti mengawal perkakasan, penderia atau peranti lain.
  • Ketahanan: aplikasi yang dibina dalam C selalunya mempunyai jangka hayat yang panjang, terutamanya dalam industri seperti peruncitan atau pembuatan.

Memperkenalkan libcurl: alat untuk HTTP dalam C

Untuk menggunakan API dalam C, libcurl ialah perpustakaan yang boleh digunakan. Ia merupakan perpustakaan sumber terbuka, mudah alih dan kaya dengan ciri untuk mengendalikan permintaan rangkaian melalui HTTP, HTTPS, FTP dan banyak lagi. Ia menyokong:

  • Membuat GET, POST dan permintaan HTTP yang lain.
  • Mengendalikan pengepala dan pengesahan.
  • Memproses respons dengan cekap.

Langkah asas untuk menggunakan API dalam C

Mari kita jalani proses menggunakan API menggunakan C, memfokuskan pada contoh dunia sebenar untuk mengambil data JSON.

Persediaan dan pemasangan

Untuk menggunakan libcurl, anda perlu memasangnya pada sistem anda. Untuk kebanyakan pengedaran Linux, ini boleh dilakukan dengan:

sudo apt-get install libcurl4-openssl-dev

Pada Windows, anda boleh memuat turun binari yang telah dikompilasi daripada tapak web libcurl: https://curl.se/download.html

Pada macOS jika anda menggunakan Homebrew anda boleh memasangnya melalui

brew install curl

Menstruktur program C anda

Atur cara C mudah untuk mengambil data daripada API melibatkan komponen berikut:

  • Memulakan libcurl.
  • Mengkonfigurasi permintaan API (URL, kaedah HTTP, pengepala, dll.).
  • Menerima dan menyimpan respons.
  • Membersihkan sumber.

Berikut ialah contoh program untuk mengambil data JSON daripada API awam:

sudo apt-get install libcurl4-openssl-dev

Langkah untuk berlari

Simpan kod dalam fail, cth., get.c.
Susunnya dengan arahan berikut:

brew install curl

Jalankan atur cara yang disusun:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl>

// Struct to hold response data
struct Memory {
    char *response;
    size_t size;
};

// Callback function to handle the data received from the API
static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t totalSize = size * nmemb;
    struct Memory *mem = (struct Memory *)userp;

    printf(". %zu %zu\n", size, nmemb);
    char *ptr = realloc(mem->response, mem->size + totalSize + 1);
    if (ptr == NULL) {
        printf("Not enough memory to allocate buffer.\n");
        return 0;
    }

    mem->response = ptr;
    memcpy(&(mem->response[mem->size]), contents, totalSize);
    mem->size += totalSize;
    mem->response[mem->size] = '<pre class="brush:php;toolbar:false">gcc get.c -o get -lcurl
'; return totalSize; } int main() { CURL *curl; CURLcode res; struct Memory chunk; chunk.response = malloc(1); // Initialize memory chunk.size = 0; // No data yet curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // Set URL of the API endpoint char access_token[] = "your-access-token"; char slug[] = "home"; char version[]= "draft"; char url[256]; snprintf(url, sizeof(url), "https://api.storyblok.com/v2/cdn/stories/%s?version=%s&token=%s", slug, version, access_token); // Print the URL printf("URL: %s\n", url); // initializing libcurl // setting the URL curl_easy_setopt(curl, CURLOPT_URL, url ); // Follow redirect curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Set callback function to handle response data curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ResponseCallback); // Pass the Memory struct to the callback function curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); // Perform the HTTP GET request res = curl_easy_perform(curl); // Check for errors if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } else { printf("Response data size: %zu\n", chunk.size); //printf("Response data: \n%s\n", chunk.response); } // Cleanup curl_easy_cleanup(curl); } // Free allocated memory free(chunk.response); curl_global_cleanup(); return 0; }

Memahami mekanisme panggil balik dalam respons HTTP dengan libcurl

Apabila bekerja dengan libcurl untuk mengendalikan respons HTTP dalam C, adalah penting untuk memahami gelagat fungsi panggil balik. Fungsi panggil balik yang anda tentukan untuk memproses data respons, seperti fungsi ResponseCallback, boleh digunakan beberapa kali untuk satu respons HTTP. Inilah sebab dan cara ini berfungsi.

Mengapakah panggilan balik dipanggil beberapa kali?

Mekanisme panggil balik dalam libcurl direka untuk mengendalikan data dengan cekap dan fleksibel. Daripada menunggu keseluruhan respons dimuat turun sebelum memprosesnya, libcurl memproses respons dalam bahagian yang lebih kecil, memanggil fungsi panggil balik anda apabila setiap bahagian diterima.

Tingkah laku ini membolehkan:

  • Penggunaan Memori yang Cekap: dengan memproses ketulan secara berperingkat, anda mengelakkan keperluan untuk memperuntukkan blok memori yang besar di hadapan untuk keseluruhan respons.
  • Pemprosesan Strim: anda boleh memproses atau bertindak pada setiap bahagian apabila ia tiba, yang berguna untuk menstrim respons besar atau mengendalikan data dalam masa nyata.

Bagaimana Ia Berfungsi?
Setiap kali sebahagian daripada data diterima daripada pelayan, libcurl memanggil fungsi panggil balik anda. Saiz setiap bahagian bergantung pada keadaan rangkaian, saiz penimbal dan logik dalaman libcurl.
Panggilan balik perlu mengumpul ketulan, akhirnya membina semula respons penuh.

Berikut ialah urutan contoh:

  1. Pelayan mula menghantar respons.
  2. libcurl menerima bahagian pertama dan memanggil panggilan balik.
  3. Panggil balik memproses atau menyimpan bongkah.
  4. libcurl menerima bahagian seterusnya dan memanggil panggilan balik semula.
  5. Proses ini berterusan sehingga keseluruhan respons diterima.

Penjelasan kod sumber langkah demi langkah untuk fungsi ResponseCallback

ResponeCallback ialah fungsi yang dipanggil apabila data diterima oleh libcurl.

Pengisytiharan Fungsi

sudo apt-get install libcurl4-openssl-dev
  • void *kandungan: ini adalah penunjuk kepada data yang diterima daripada pelayan. libcurl menyediakan penimbal ini dan mengisinya dengan data yang dimuat turunnya.
  • size_t size dan size_t nmemb: Ini mewakili saiz setiap blok memori (saiz) dan bilangan blok (nmemb). Bersama-sama, saiz * nmemb memberikan jumlah saiz data yang diterima dalam bahagian ini.
  • void *userp: ini adalah penunjuk yang ditentukan pengguna yang dihantar ke fungsi panggil balik melalui curl_easy_setopt(curl, CURLOPT_WRITEDATA, ...). Dalam contoh ini, ia adalah penunjuk kepada objek Memori struktur, yang menyimpan respons penuh.

Kira jumlah saiz data

brew install curl

Ini mengira jumlah saiz bahagian semasa data yang diterima dengan mendarabkan saiz satu blok (saiz) dengan bilangan blok (nmemb).
Sebagai contoh, jika pelayan menghantar 8 blok 256 bait setiap satu, jumlah Saiz ialah 8 * 256 = 2048 bait.

Akses data pengguna (struktur Memori)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl>

// Struct to hold response data
struct Memory {
    char *response;
    size_t size;
};

// Callback function to handle the data received from the API
static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t totalSize = size * nmemb;
    struct Memory *mem = (struct Memory *)userp;

    printf(". %zu %zu\n", size, nmemb);
    char *ptr = realloc(mem->response, mem->size + totalSize + 1);
    if (ptr == NULL) {
        printf("Not enough memory to allocate buffer.\n");
        return 0;
    }

    mem->response = ptr;
    memcpy(&(mem->response[mem->size]), contents, totalSize);
    mem->size += totalSize;
    mem->response[mem->size] = '<pre class="brush:php;toolbar:false">gcc get.c -o get -lcurl
'; return totalSize; } int main() { CURL *curl; CURLcode res; struct Memory chunk; chunk.response = malloc(1); // Initialize memory chunk.size = 0; // No data yet curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // Set URL of the API endpoint char access_token[] = "your-access-token"; char slug[] = "home"; char version[]= "draft"; char url[256]; snprintf(url, sizeof(url), "https://api.storyblok.com/v2/cdn/stories/%s?version=%s&token=%s", slug, version, access_token); // Print the URL printf("URL: %s\n", url); // initializing libcurl // setting the URL curl_easy_setopt(curl, CURLOPT_URL, url ); // Follow redirect curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Set callback function to handle response data curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ResponseCallback); // Pass the Memory struct to the callback function curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); // Perform the HTTP GET request res = curl_easy_perform(curl); // Check for errors if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } else { printf("Response data size: %zu\n", chunk.size); //printf("Response data: \n%s\n", chunk.response); } // Cleanup curl_easy_cleanup(curl); } // Free allocated memory free(chunk.response); curl_global_cleanup(); return 0; }

Penunjuk userp dihantar ke struct Memory *. Struk ini telah diluluskan lebih awal dalam atur cara utama dan digunakan untuk mengumpul data yang diterima.

Struktur Memori ditakrifkan sebagai:

./get
  • respons: rentetan yang diperuntukkan secara dinamik yang menyimpan data yang dimuat turun.
  • saiz: saiz semasa rentetan tindak balas.

Alokasikan semula ingatan

static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp)

Mengubah saiz penimbal tindak balas untuk menampung bahagian data baharu:

  • mem->saiz: saiz penimbal semasa.
  • jumlahSaiz: Saiz bongkah baharu.
  • 1: Ruang untuk penamat-null ( ) untuk menjadikannya rentetan C yang sah.
  • realloc: memperuntukkan semula memori secara dinamik untuk penimbal tindak balas.

Jika peruntukan gagal, realloc mengembalikan NULL, dan memori lama kekal sah.

Mengendalikan ralat peruntukan memori

size_t totalSize = size * nmemb;

Jika peruntukan memori gagal (jadi ptr ialah NULL), cetak mesej ralat dan kembalikan 0. Mengembalikan 0 isyarat libcurl untuk membatalkan pemindahan.

Kemas kini penimbal

struct Memory *mem = (struct Memory *)userp;
  • mem->response = ptr: tetapkan memori yang baru diperuntukkan kembali kepada penunjuk respons.
  • memcpy: salin bahagian baru data daripada kandungan ke dalam penimbal:
    • &(mem->response[mem->size]): Lokasi dalam penimbal tempat data baharu harus dilampirkan (penghujung data semasa).
    • kandungan: Data yang diterima daripada pelayan.
    • totalSize: Saiz data untuk disalin.

Kemas kini jumlah saiz

struct Memory {
    char *response;
    size_t size;
};

Naikkan saiz penimbal tindak balas untuk mencerminkan jumlah saiz baharu selepas menambahkan bahagian baharu.

Null-Tamatkan rentetan tindak balas

sudo apt-get install libcurl4-openssl-dev

Tambahkan penamat nol pada penghujung penimbal respons untuk menjadikannya rentetan C yang sah.
Ini memastikan bahawa respons boleh dianggap dengan selamat sebagai rentetan yang ditamatkan nol biasa.

Kembalikan jumlah saiz

brew install curl

Kembalikan bilangan bait yang diproses (totalSize).
Ini memberi isyarat kepada libcurl bahawa bongkah data telah dikendalikan dengan jayanya.

Bila hendak memilih C untuk API

Gunakan C untuk menggunakan API apabila:

  • Perkara Prestasi: C sesuai untuk aplikasi kritikal kelajuan.
  • Penyatuan Sistem: anda perlu menggabungkan permintaan rangkaian dengan operasi perkakasan (cth., mengambil data untuk sistem PoS).
  • Sistem Terbenam: peranti yang dikekang sumber mendapat manfaat daripada kecekapan C.
  • Perasaan ingin tahu dan penerokaan: Kadangkala, anda menggunakan C semata-mata kerana anda menikmati pengaturcaraan dan ingin mencabar diri anda dengan meneroka bahasa peringkat rendah untuk tugasan yang sering dikhaskan untuk tugasan yang lebih tinggi. Ini adalah cara yang bagus untuk memperdalam pemahaman anda tentang cara sesuatu berfungsi di bawah hud!

Kesimpulan

Penggunaan API dalam C mungkin kelihatan tidak konvensional dalam dunia pengaturcaraan peringkat tinggi hari ini, tetapi ia merupakan alat yang berkuasa untuk senario yang memerlukan prestasi, kawalan dan penyepaduan dengan operasi peringkat sistem. Dengan menggunakan perpustakaan seperti libcurl, pembangun boleh dengan mudah menyepadukan permintaan HTTP ke dalam aplikasi C, merapatkan jurang antara API moden dan pengaturcaraan peringkat sistem tradisional.

Dengan pengetahuan ini, anda boleh membina aplikasi C yang berinteraksi dengan lancar dengan API, membuktikan bahawa C kekal relevan walaupun dalam aliran kerja pembangunan moden.

Atas ialah kandungan terperinci Menggunakan API dalam C: panduan praktikal untuk pembangun moden. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
C# vs C: Pengaturcaraan dan ciri berorientasikan objekC# vs C: Pengaturcaraan dan ciri berorientasikan objekApr 17, 2025 am 12:02 AM

Terdapat perbezaan yang signifikan dalam bagaimana C# dan C melaksanakan dan ciri-ciri dalam pengaturcaraan berorientasikan objek (OOP). 1) Definisi kelas dan sintaks C# lebih ringkas dan menyokong ciri -ciri canggih seperti LINQ. 2) C menyediakan kawalan berbutir yang lebih baik, sesuai untuk pengaturcaraan sistem dan keperluan prestasi tinggi. Kedua -duanya mempunyai kelebihan mereka sendiri, dan pilihannya harus berdasarkan senario aplikasi tertentu.

Dari XML ke C: Transformasi dan Manipulasi DataDari XML ke C: Transformasi dan Manipulasi DataApr 16, 2025 am 12:08 AM

Menukar dari XML ke C dan melakukan operasi data boleh dicapai melalui langkah -langkah berikut: 1) Parsing Fail XML menggunakan perpustakaan TinyXML2, 2) Pemetaan data ke dalam struktur data C, 3) Menggunakan perpustakaan standard C seperti STD :: Vektor untuk operasi data. Melalui langkah -langkah ini, data yang ditukar dari XML boleh diproses dan dimanipulasi dengan cekap.

C# vs C: Pengurusan memori dan koleksi sampahC# vs C: Pengurusan memori dan koleksi sampahApr 15, 2025 am 12:16 AM

C# menggunakan mekanisme pengumpulan sampah automatik, manakala C menggunakan pengurusan memori manual. 1. Pemungut Sampah C 2.C menyediakan kawalan memori yang fleksibel, sesuai untuk aplikasi yang memerlukan pengurusan yang baik, tetapi harus dikendalikan dengan berhati -hati untuk mengelakkan kebocoran ingatan.

Di luar gembar -gembur: Menilai kaitan C hari iniDi luar gembar -gembur: Menilai kaitan C hari iniApr 14, 2025 am 12:01 AM

C masih mempunyai kaitan penting dalam pengaturcaraan moden. 1) Keupayaan operasi prestasi tinggi dan perkakasan langsung menjadikannya pilihan pertama dalam bidang pembangunan permainan, sistem tertanam dan pengkomputeran berprestasi tinggi. 2) Paradigma pengaturcaraan yang kaya dan ciri -ciri moden seperti penunjuk pintar dan pengaturcaraan templat meningkatkan fleksibiliti dan kecekapannya. Walaupun lengkung pembelajaran curam, keupayaannya yang kuat menjadikannya masih penting dalam ekosistem pengaturcaraan hari ini.

Komuniti C: Sumber, Sokongan, dan PembangunanKomuniti C: Sumber, Sokongan, dan PembangunanApr 13, 2025 am 12:01 AM

C Pelajar dan pemaju boleh mendapatkan sumber dan sokongan dari StackOverflow, Komuniti R/CPP Reddit, Coursera dan EDX, Projek Sumber Terbuka di GitHub, Perkhidmatan Perundingan Profesional, dan CPPCON. 1. StackOverflow memberikan jawapan kepada soalan teknikal; 2. Komuniti R/CPP Reddit berkongsi berita terkini; 3. Coursera dan EDX menyediakan kursus f rasmi; 4. Projek sumber terbuka pada GitHub seperti LLVM dan meningkatkan kemahiran meningkatkan; 5. Perkhidmatan perundingan profesional seperti jetbrains dan perforce menyediakan sokongan teknikal; 6. CPPCON dan persidangan lain membantu kerjaya

C# vs C: di mana setiap bahasa cemerlangC# vs C: di mana setiap bahasa cemerlangApr 12, 2025 am 12:08 AM

C# sesuai untuk projek yang memerlukan kecekapan pembangunan tinggi dan sokongan silang platform, manakala C sesuai untuk aplikasi yang memerlukan prestasi tinggi dan kawalan asas. 1) C# Memudahkan pembangunan, menyediakan pengumpulan sampah dan perpustakaan kelas yang kaya, sesuai untuk aplikasi peringkat perusahaan. 2) C membolehkan operasi memori langsung, sesuai untuk pembangunan permainan dan pengkomputeran berprestasi tinggi.

Penggunaan berterusan C: Sebab -sebab ketahanannyaPenggunaan berterusan C: Sebab -sebab ketahanannyaApr 11, 2025 am 12:02 AM

C Alasan penggunaan berterusan termasuk prestasi tinggi, aplikasi luas dan ciri -ciri yang berkembang. 1) Prestasi kecekapan tinggi: C melaksanakan dengan baik dalam pengaturcaraan sistem dan pengkomputeran berprestasi tinggi dengan terus memanipulasi memori dan perkakasan. 2) Digunakan secara meluas: bersinar dalam bidang pembangunan permainan, sistem tertanam, dan lain -lain. 3) Evolusi berterusan: Sejak pembebasannya pada tahun 1983, C terus menambah ciri -ciri baru untuk mengekalkan daya saingnya.

Masa Depan C dan XML: Trend dan Teknologi MunculMasa Depan C dan XML: Trend dan Teknologi MunculApr 10, 2025 am 09:28 AM

Trend pembangunan masa depan C dan XML adalah: 1) C akan memperkenalkan ciri -ciri baru seperti modul, konsep dan coroutin melalui piawaian C 20 dan C 23 untuk meningkatkan kecekapan dan keselamatan pengaturcaraan; 2) XML akan terus menduduki kedudukan penting dalam pertukaran data dan fail konfigurasi, tetapi akan menghadapi cabaran JSON dan YAML, dan akan berkembang dengan lebih ringkas dan mudah untuk menghuraikan arahan, seperti penambahbaikan XMLSChema1.1 dan XPath3.1.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
1 bulan yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
1 bulan yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
1 bulan yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Arahan sembang dan cara menggunakannya
1 bulan yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

SecLists

SecLists

SecLists ialah rakan penguji keselamatan muktamad. Ia ialah koleksi pelbagai jenis senarai yang kerap digunakan semasa penilaian keselamatan, semuanya di satu tempat. SecLists membantu menjadikan ujian keselamatan lebih cekap dan produktif dengan menyediakan semua senarai yang mungkin diperlukan oleh penguji keselamatan dengan mudah. Jenis senarai termasuk nama pengguna, kata laluan, URL, muatan kabur, corak data sensitif, cangkerang web dan banyak lagi. Penguji hanya boleh menarik repositori ini ke mesin ujian baharu dan dia akan mempunyai akses kepada setiap jenis senarai yang dia perlukan.

PhpStorm versi Mac

PhpStorm versi Mac

Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).

DVWA

DVWA

Damn Vulnerable Web App (DVWA) ialah aplikasi web PHP/MySQL yang sangat terdedah. Matlamat utamanya adalah untuk menjadi bantuan bagi profesional keselamatan untuk menguji kemahiran dan alatan mereka dalam persekitaran undang-undang, untuk membantu pembangun web lebih memahami proses mengamankan aplikasi web, dan untuk membantu guru/pelajar mengajar/belajar dalam persekitaran bilik darjah Aplikasi web keselamatan. Matlamat DVWA adalah untuk mempraktikkan beberapa kelemahan web yang paling biasa melalui antara muka yang mudah dan mudah, dengan pelbagai tahap kesukaran. Sila ambil perhatian bahawa perisian ini

Dreamweaver Mac版

Dreamweaver Mac版

Alat pembangunan web visual

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual