Panggilan balik dalam C adalah fungsi yang disediakan untuk fungsi lain untuk "memanggil kembali ke" di beberapa titik ketika fungsi lain melakukan tugasnya.
Ada dua cara callback digunakan : callback sinkron dan callback asinkron. Callback sinkron disediakan untuk fungsi lain yang akan melakukan beberapa tugas dan kemudian kembali ke pemanggil dengan tugas selesai. Callback asinkron disediakan untuk fungsi lain yang akan memulai tugas dan kemudian kembali ke pemanggil dengan tugas yang mungkin tidak selesai.
Callback sinkron biasanya digunakan untuk memberikan delegasi ke fungsi lain yang fungsi lain mendelegasikan beberapa langkah tugas. Contoh klasik dari delegasi ini adalah fungsi bsearch()
dan qsort()
dari C Standard Library. Kedua fungsi ini mengambil panggilan balik yang digunakan selama tugas fungsi menyediakan sehingga jenis data yang dicari, dalam kasus bsearch()
, atau diurutkan, dalam kasus qsort()
, tidak perlu diketahui oleh fungsi yang sedang bekas.
Misalnya di sini adalah program sampel kecil dengan bsearch()
menggunakan berbagai fungsi perbandingan, panggilan balik sinkron. Dengan memungkinkan kami mendelegasikan perbandingan data ke fungsi panggilan balik, bsearch()
fungsi ini memungkinkan kami untuk memutuskan pada waktu berjalan perbandingan apa yang ingin kami gunakan. Ini sinkron karena ketika bsearch()
fungsi mengembalikan tugas selesai.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int iValue;
int kValue;
char label[6];
} MyData;
int cmpMyData_iValue (MyData *item1, MyData *item2)
{
if (item1->iValue < item2->iValue) return -1;
if (item1->iValue > item2->iValue) return 1;
return 0;
}
int cmpMyData_kValue (MyData *item1, MyData *item2)
{
if (item1->kValue < item2->kValue) return -1;
if (item1->kValue > item2->kValue) return 1;
return 0;
}
int cmpMyData_label (MyData *item1, MyData *item2)
{
return strcmp (item1->label, item2->label);
}
void bsearch_results (MyData *srch, MyData *found)
{
if (found) {
printf ("found - iValue = %d, kValue = %d, label = %s\n", found->iValue, found->kValue, found->label);
} else {
printf ("item not found, iValue = %d, kValue = %d, label = %s\n", srch->iValue, srch->kValue, srch->label);
}
}
int main ()
{
MyData dataList[256] = {0};
{
int i;
for (i = 0; i < 20; i++) {
dataList[i].iValue = i + 100;
dataList[i].kValue = i + 1000;
sprintf (dataList[i].label, "%2.2d", i + 10);
}
}
// ... some code then we do a search
{
MyData srchItem = { 105, 1018, "13"};
MyData *foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_iValue );
bsearch_results (&srchItem, foundItem);
foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_kValue );
bsearch_results (&srchItem, foundItem);
foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_label );
bsearch_results (&srchItem, foundItem);
}
}
Callback asinkron berbeda karena ketika fungsi yang dipanggil di mana kami memberikan panggilan balik, tugas mungkin tidak selesai. Jenis panggilan balik ini sering digunakan dengan I / O asinkron di mana operasi I / O dimulai dan kemudian ketika selesai, panggilan balik dipanggil.
Dalam program berikut ini kami membuat soket untuk mendengarkan permintaan koneksi TCP dan ketika permintaan diterima, fungsi melakukan mendengarkan kemudian memanggil fungsi panggilan balik yang disediakan. Aplikasi sederhana ini dapat dilakukan dengan menjalankannya di satu jendela saat menggunakan telnet
utilitas atau browser web untuk mencoba terhubung di jendela lain.
Saya mengangkat sebagian besar kode WinSock dari contoh yang disediakan Microsoft dengan accept()
fungsi di https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx
Aplikasi ini memulai listen()
pada host lokal, 127.0.0.1, menggunakan port 8282 sehingga Anda dapat menggunakan salah satu telnet 127.0.0.1 8282
atau http://127.0.0.1:8282/
.
Aplikasi sampel ini dibuat sebagai aplikasi konsol dengan Visual Studio 2017 Community Edition dan menggunakan soket versi Microsoft WinSock. Untuk aplikasi Linux, fungsi WinSock perlu diganti dengan alternatif Linux dan pustaka thread Windows akan digunakan pthreads
sebagai gantinya.
#include <stdio.h>
#include <winsock2.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
// function for the thread we are going to start up with _beginthreadex().
// this function/thread will create a listen server waiting for a TCP
// connection request to come into the designated port.
// _stdcall modifier required by _beginthreadex().
int _stdcall ioThread(void (*pOutput)())
{
//----------------------
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup failed with error: %ld\n", iResult);
return 1;
}
//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
SOCKET ListenSocket;
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
struct sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(8282);
if (bind(ListenSocket, (SOCKADDR *)& service, sizeof(service)) == SOCKET_ERROR) {
printf("bind failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
//----------------------
// Listen for incoming connection requests.
// on the created socket
if (listen(ListenSocket, 1) == SOCKET_ERROR) {
printf("listen failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
//----------------------
// Create a SOCKET for accepting incoming requests.
SOCKET AcceptSocket;
printf("Waiting for client to connect...\n");
//----------------------
// Accept the connection.
AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
printf("accept failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
else
pOutput (); // we have a connection request so do the callback
// No longer need server socket
closesocket(ListenSocket);
WSACleanup();
return 0;
}
// our callback which is invoked whenever a connection is made.
void printOut(void)
{
printf("connection received.\n");
}
#include <process.h>
int main()
{
// start up our listen server and provide a callback
_beginthreadex(NULL, 0, ioThread, printOut, 0, NULL);
// do other things while waiting for a connection. In this case
// just sleep for a while.
Sleep(30000);
}