C Academy · Pelajaran

Loop Peristiwa

Tanggapi soket yang dapat dibaca.

Pelajaran 3 dari 413 langkah

Loop Peristiwa adalah pelajaran C Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C Academy mencakup 4 pelajaran total.

Inti Server

Perulangan peristiwa adalah mesin yang menggerakkan server epoll. Perulangan ini berulang kali menunggu deskriptor yang siap dan meneruskan pekerjaan ke penangan.

Bentuknya selalu sama: panggil epoll_wait(), iterasikan peristiwa yang dikembalikan, tangani masing-masing, lalu ulangi lagi. Semua hal lainnya bergantung pada kerangka ini.

for (;;) {
    int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
    for (int i = 0; i < n; i++) handle(&events[i]);
}

Memanggil epoll_wait

epoll_wait() menerima fd epoll, larik keluaran berisi epoll_event, kapasitasnya, dan batas waktu dalam milidetik.

Fungsi ini memblokir hingga setidaknya satu deskriptor siap (atau batas waktu tercapai), lalu mengembalikan jumlah peristiwa yang diisi ke dalam larik Anda. Hanya entri tersebut yang valid.

struct epoll_event events[MAX_EVENTS];
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
if (n == -1) { perror("epoll_wait"); }

Argumen Batas Waktu

Batas waktu -1 memblokir tanpa batas hingga sebuah peristiwa tiba. Nilai 0 langsung mengembalikan hasil dengan melakukan pemeriksaan tanpa tidur.

Nilai positif membatasi lamanya menunggu, yang berguna jika Anda juga perlu menjalankan tugas berkala seperti mengosongkan catatan atau mengakhiri koneksi yang menganggur.

int n = epoll_wait(epfd, events, MAX_EVENTS, 1000); /* up to 1s */
if (n == 0) run_periodic_tasks();

Menentukan Ukuran Larik Peristiwa

Kapasitas larik membatasi jumlah peristiwa siap yang dapat dilaporkan oleh satu pemanggilan epoll_wait(). Jika ada lebih banyak peristiwa yang siap, sisanya dikembalikan pada pemanggilan berikutnya.

Ukuran sedang seperti 64 atau 1024 sudah memadai; epoll membagi giliran secara adil di antara peristiwa tertunda pada berbagai pemanggilan, sehingga tidak ada yang terabaikan.

#define MAX_EVENTS 64
struct epoll_event events[MAX_EVENTS];

Meneruskan Peristiwa pada Soket Pendengar

Di dalam perulangan, pertama-tama periksa apakah deskriptor yang siap adalah soket pendengar Anda. Jika ya, berarti ada koneksi baru yang menunggu.

Anda menerimanya, mengaturnya agar tidak memblokir, lalu mendaftarkannya ke epoll. Semua deskriptor lainnya adalah klien yang sudah ada, dengan data untuk dibaca atau ruang untuk ditulisi.

if (events[i].data.fd == listen_fd) {
    accept_new_connections(epfd, listen_fd);
} else {
    handle_client(epfd, &events[i]);
}

Menerima Koneksi dalam Perulangan

Satu peristiwa kesiapan pada soket pendengar dapat berarti ada beberapa koneksi yang menunggu. Lakukan perulangan pada accept() hingga fungsi tersebut mengembalikan EAGAIN.

Hal ini sangat penting dalam mode pemicu tepi dan merupakan praktik yang baik di mana pun, agar klien tidak perlu menunggu hingga pembangkitan berikutnya.

for (;;) {
    int c = accept(listen_fd, NULL, NULL);
    if (c == -1) { if (errno == EAGAIN) break; else break; }
    set_nonblocking(c);
    add_to_epoll(epfd, c);
}

Menangani Peristiwa yang Dapat Dibaca

Saat EPOLLIN terpicu pada klien, bacalah dari klien tersebut. Dalam mode pemicu tingkat, satu recv() untuk setiap pembangkitan sudah dapat diterima.

Nilai kembalian 0 berarti klien menutup koneksi: bersihkan sumber dayanya. Nilai negatif dengan EAGAIN berarti semua data yang tersedia untuk saat ini telah dibaca.

ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r == 0) { close_conn(epfd, fd); }
else if (r > 0) { process(buf, r); }

Mengosongkan Data dalam Mode Pemicu Tepi

Dengan EPOLLET, Anda harus membaca hingga recv() mengembalikan EAGAIN. Kernel hanya memberi tahu Anda saat terjadi perubahan menjadi dapat dibaca, sehingga byte yang tersisa akan terabaikan hingga terjadi perubahan berikutnya.

Bungkus pembacaan dalam sebuah perulangan dan keluar hanya saat mendapatkan EAGAIN atau akhir aliran.

for (;;) {
    ssize_t r = recv(fd, buf, sizeof buf, 0);
    if (r > 0) process(buf, r);
    else if (r == 0) { close_conn(epfd, fd); break; }
    else { if (errno == EAGAIN) break; else { close_conn(epfd, fd); break; } }
}

Menangani Peristiwa yang Dapat Ditulisi

EPOLLOUT terpicu saat soket dapat menerima lebih banyak data keluar. Anda hanya menginginkannya ketika ada byte tersangga yang sebelumnya belum terkirim sepenuhnya.

Kosongkan penyangga Anda; setelah kosong, ubah kembali minat hanya menjadi EPOLLIN dengan EPOLL_CTL_MOD untuk menghindari arus peristiwa siap tulis yang terus-menerus.

if (events[i].events & EPOLLOUT) {
    flush_pending(fd);
    if (buffer_empty(fd)) watch_read_only(epfd, fd);
}

Menangani Penantian yang Terinterupsi

epoll_wait() dapat mengembalikan -1 dengan errno == EINTR jika sebuah sinyal menginterupsinya. Ini bukan kesalahan sebenarnya; cukup coba lagi.

Perulangan yang tangguh melanjutkan proses saat mendapatkan EINTR dan hanya menganggap kode kesalahan lain sebagai fatal. Lupa menangani hal ini dapat membuat server mogok saat pertama kali menerima sinyal.

int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
if (n == -1) {
    if (errno == EINTR) continue;
    perror("epoll_wait"); break;
}

Satu Perulangan, Banyak Klien

Gabungkan semuanya, dan satu utas berputar selamanya melalui deskriptor yang siap: menerima, membaca, menulis, menutup, lalu mengulanginya.

Karena utas tidur di dalam epoll_wait() saat tidak ada aktivitas dan hanya memproses pekerjaan yang siap saat sibuk, rancangan ini dapat menangani puluhan ribu koneksi serentak dengan nyaman.

Pemeriksaan Singkat

Uji pemahaman Anda tentang perulangan peristiwa.

Rangkuman

Perulangan peristiwa memanggil epoll_wait(), mengiterasikan peristiwa yang siap, lalu meneruskannya: menerima pada soket pendengar, membaca pada EPOLLIN, mengosongkan penyangga pada EPOLLOUT, dan membersihkan sumber daya saat hangup.

Lakukan perulangan pada penerimaan dan pembacaan, coba lagi saat mendapatkan EINTR, dan kosongkan sepenuhnya dalam mode EPOLLET. Selanjutnya, kita merakit server echo lengkap.

Gratis untuk memulai

Belajar C dengan tutor AI — gratis

Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.

Kursus
39
Pelajaran
144

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Loop Peristiwa” gratis?

Ya — teks lengkap “Loop Peristiwa” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C Academy, upgrade ke CoddyKit PRO. Kursus C Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Loop Peristiwa”?

Tanggapi soket yang dapat dibaca. Kamu berlatih C Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai C Academy?

Tidak diperlukan pengalaman sebelumnya. C Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.

Berapa lama pelajaran “Loop Peristiwa” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran C Academy ini?

Ya. Setiap pelajaran C Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. I/O Memblokir vs Tidak Memblokir
  2. Menyiapkan epoll
  3. Loop Peristiwa
  4. Server Echo Sederhana
← Kembali ke C Academy