C'deki geri arama, diğer işlev görevini yaparken bir noktada "geri aramak" için başka bir işleve sağlanan bir işlevdir.
Orada bir geri arama kullanılan iki yöntem senkron geri arama ve asenkron geri arama. Bazı görevleri yerine getirecek ve daha sonra görev tamamlandığında arayan kişiye geri dönecek olan başka bir işleve eşzamanlı geri çağrı sağlanır. Bir görevi başlatacak ve sonra muhtemelen tamamlanmamış görevle arayana geri dönecek olan başka bir işleve eşzamansız geri çağrı sağlanır.
Eşzamanlı geri arama genellikle, diğer işlevin görevin bir adımını devrettiği başka bir işleve bir temsilci sağlamak için kullanılır. Bu heyet Klasik örnekler fonksiyonları bsearch()
ve qsort()
C Standart Kütüphanesi'nden. Bu işlevlerin her ikisi de, işlevin sağladığı görev sırasında kullanılan bir geri çağrıyı alır, böylece aranan bsearch()
veya tür olması durumunda aranan verilerin türünün qsort()
işlev tarafından bilinmesine gerek kalmaz Kullanılmış.
Örneğin, burada bsearch()
farklı karşılaştırma fonksiyonları, senkron geri çağrılar kullanan küçük bir örnek program bulunmaktadır . Veri karşılaştırmasını bir geri arama işlevine devredebilmemize izin vererek, bsearch()
işlev çalışma zamanında ne tür bir karşılaştırma kullanmak istediğimize karar vermemizi sağlar. Bu bsearch()
işlev zaman uyumludur çünkü işlev döndüğünde görev tamamlanmıştır.
#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);
}
}
Zaman uyumsuz bir geri arama, geri arama sağladığımız çağrılan işlev döndüğünde, görevin tamamlanmayabileceğinden farklıdır. Bu geri arama türü genellikle, bir G / Ç işleminin başlatıldığı ve ardından tamamlandığında geri arama başlatıldığı zaman uyumsuz G / Ç ile kullanılır.
Aşağıdaki programda TCP bağlantı isteklerini dinlemek için bir soket oluşturuyoruz ve bir istek alındığında, dinlemeyi yapan işlev daha sonra sağlanan geri arama işlevini çağırıyor. Bu basit uygulama, telnet
başka bir pencereye bağlanmaya çalışmak için yardımcı programı veya bir web tarayıcısını kullanırken bir pencerede çalıştırarak uygulanabilir.
WinSock kodunun çoğunu Microsoft'un https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx adresindekiaccept()
işlevle sağladığı örnekten kaldırdım
Bu uygulama listen()
bağlantı noktası 8282 kullanarak yerel ana bilgisayar, 127.0.0.1 üzerinde başlar , ya telnet 127.0.0.1 8282
da kullanabilirsiniz http://127.0.0.1:8282/
.
Bu örnek uygulama, Visual Studio 2017 Community Edition ile bir konsol uygulaması olarak oluşturuldu ve soketlerin Microsoft WinSock sürümünü kullanıyor. Bir Linux uygulaması için WinSock işlevlerinin Linux alternatifleriyle değiştirilmesi gerekir ve bunun yerine Windows iş parçacığı kitaplığı kullanılır pthreads
.
#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);
}