ΔΙΑΔΙΚΑΣΙΕΣ: Αποστολή πολλαπλών byte εκτός εύρους δεδομένων με χρήση του Winsock


Σύνοψη


Μερικές φορές πρέπει να στείλετε επείγοντα δεδομένα (OOB) εκτός εύρους σας δέκτες. Δέκτες είναι χρήστες ή όλες τις εφαρμογές που θα λάβει τα δεδομένα. Θέλετε αυτά τα δεδομένα OOB αντιμετωπίζονται ως δεδομένα υψηλότερης προτεραιότητας από οποιαδήποτε δεδομένα που μπορείτε να στείλετε. Εάν τα δεδομένα OOB που θέλετε να στείλετε ένα byte, μπορείτε να χρησιμοποιήσετε τη λειτουργία " επιλογή " για αναζήτηση OOB δεδομένων. Μπορείτε να χρησιμοποιήσετε τη λειτουργία " λήψη " για να διαβάσετε τα δεδομένα.

Ωστόσο, στο πρωτόκολλο TCP (Transmission Control), το μπλοκ δεδομένων OOB είναι πάντα ένα byte. Επομένως, εάν στέλνετε δεδομένα OOB πολλαπλών byte, μόνο το τελευταίο byte των δεδομένων OOB ανακτάται. Τα υπόλοιπα δεδομένα θα θεωρηθεί ως κανονικά δεδομένα.

Αυτό το άρθρο χρησιμοποιεί το δείγμα κώδικα για να περιγράψετε τον τρόπο αποστολής πολλαπλών byte OOB δεδομένων χρησιμοποιώντας το Microsoft υποδοχές Windows (Winsock).

ΕΙΣΑΓΩΓΗ


Αυτό το άρθρο περιγράφει τον τρόπο αποστολής δεδομένων εκτός εύρους πολλαπλών-byte (χαρακτήρες) με χρήση του Winsock. Δημιουργούνται τα δείγματα εφαρμογών στη Microsoft Visual C++.

Επειδή ο μηχανισμός αυτός OOB δεν υποστηρίζεται απευθείας στο επίπεδο της Υποδοχής των Windows της Microsoft, πρέπει να εφαρμόσετε αυτόν τον μηχανισμό OOB σε επίπεδο εφαρμογής. Αυτό δεν ισχύει OOB δεδομένων. Σε αυτήν την εφαρμογή δείγματος, μπορείτε να δημιουργήσετε δύο υποδοχές στην πλευρά προγράμματος-πελάτη, γνωστή και ως η πλευρά αποστολέα, για την αποστολή δεδομένων OOB και κανονικά δεδομένα. Από την πλευρά του διακομιστή, γνωστή και ως η πλευρά του δέκτη, μπορείτε να χρησιμοποιήσετε δύο υποδοχές για την επεξεργασία των δεδομένων σε δύο νημάτων. Ένα νήμα είναι για δεδομένα OOB. Άλλο νήμα είναι κανονικά δεδομένα.


Για να εξομοιώσετε το μηχανισμό OOB, πρέπει να συγχρονίσετε αυτές τις δύο νημάτων. Βεβαιωθείτε ότι το νήμα που επεξεργάζεται δεδομένα OOB έχει υψηλότερη προτεραιότητα από το νήμα που επεξεργάζεται δεδομένα.

Σημείωση Αυτού του δείγματος εφαρμογής περιγράφει έναν τρόπο για την αποστολή δεδομένων OOB πολλαπλών byte. Ίσως χρειαστεί να αναθεωρήσετε τον κώδικα για να κάνετε τον κώδικά σας λειτουργεί στο περιβάλλον σας.

Επιστροφή στην κορυφή

Δημιουργήσετε μια εφαρμογή προγράμματος-πελάτη

  1. Για να δημιουργήσετε μια εφαρμογή προγράμματος-πελάτη. Σε αυτήν την εφαρμογή προγράμματος-πελάτη, το ακόλουθο δείγμα κώδικα περιγράφει τον τρόπο δημιουργίας δύο υποδοχές:
    SOCKET myOOBSocket = INVALID_SOCKET;
    SOCKET myNormalSocket = INVALID_SOCKET;

    myOOBSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    myNormalSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    Η μεταβλητή myOOBSocket χρησιμοποιείται για την αποστολή δεδομένων OOB. Η μεταβλητή myNormalSocket χρησιμοποιείται για την αποστολή δεδομένων κανονική.
  2. Επειδή τα δεδομένα που στέλνει η μεταβλητή myOOBSocket δεν είναι αληθής OOB δεδομένων, πρέπει να έχετε ένα τρόπο για να ενημερώσει το διακομιστή το είδος των δεδομένων που υποτίθεται ότι η Υποδοχή για την αποστολή πριν να ξεκινήσετε την αποστολή των δεδομένων. Το ακόλουθο δείγμα κώδικα περιγράφει τον τρόπο αποστολής ενός αρχικός χαρακτήρας για να ενημερώσετε το διακομιστή σχετικά με το είδος των δεδομένων που θα αποσταλούν. Χρήση "U" για δεδομένα OOB και χρήση "N" για κανονική δεδομένα.
    int nErr, nSize;
    nErr = connect(myNormalSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));
    //Look for a potential error here.
    //"remoteIp" is the remote address.
    nSize = send(myNormalSocket, "N",1, 0);
    //Look for a potential error here.

    nErr = connect(myOOBSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));
    //Look for a potential error here.
    nSize = send(myOOBSocket,"U",1, 0);
    //Look for a potential error here.
  3. Το ακόλουθο δείγμα κώδικα περιγράφει τον τρόπο ορισμού της εφαρμογής-πελάτη που παρακολουθούν τα δεδομένα εισόδου από το χρήστη. Η εφαρμογή-πελάτης στέλνει κεφαλαίους χαρακτήρες ως OOB δεδομένα. Διπλότυπο κάθε χαρακτήρας εισόδου για να συνθέσετε μια ακολουθία χαρακτήρων πολλών byte.
    for (;;) {
    int ch = _getch();
    _putch( ch );
    if (ch=='.') {
    shutdown(myOOBSocket, 2);
    shutdown(myNormalSocket,2);
    break;
    }
    char buf[10];
    memset(buf, ch, sizeof(buf));

    if (isupper(ch)) {
    nSize = send(myOOBSocket, buf, sizeof(buf), 0);
    //Do not use the MSG_OOB flag. Send it as normal data.
    } else {
    nSize = send(myNormalSocket, buf, sizeof(buf), 0);
    }
    ...
    }
Εμφανίζει το δείγμα κώδικα για την εφαρμογή του προγράμματος-πελάτη, Myclient.cpp

Επιστροφή στην κορυφή

Δημιουργία μιας εφαρμογής διακομιστή

  1. Από την πλευρά του διακομιστή, το ακόλουθο δείγμα κώδικα περιγράφει τον τρόπο δημιουργίας μιας υποδοχής παρακολούθησης για την εποπτεία της θύρας που χρησιμοποιείται για την επικοινωνία:
    int nErr;
    SOCKET myListener = INVALID_SOCKET;

    myListener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    //Look for a potential return error here.

    nErr = bind(myListener,(SOCKADDR *)&localIp,sizeof(localIp));
    //Look for a potential return error here.
    //"localIp" is the local address of the server.

    nErr = listen(myListener, 5);
    //Look for a potential return error here.
  2. Το ακόλουθο δείγμα κώδικα περιγράφει πώς μπορείτε να καλέσετε τη συνάρτηση Αποδοχή πραγματοποίησης της υποδοχής παρακολούθησης περιμένετε προσπαθεί εισερχόμενης σύνδεσης:
    for (;;) {
    struct sockaddr_in remoteIp;
    SOCKET remoteSocket = INVALID_SOCKET;
    int nAddrLen = sizeof(SOCKADDR);

    remoteSocket = accept(myListener, (SOCKADDR *)(&remoteIp), &nAddrLen);
    //"remoteIp" is a pointer to a buffer that receives
    //the address of the connecting entity.

    BYTE buffer[1+1];
    int recv_len=recv(remoteSocket,(char *)&buffer,1,0);
    //This supposes that the client sockets will send
    //"U" or "N" as the initial character.

    buffer[recv_len] = '\0';
    if(strcmp((char *)buffer,"U")==0)
    hThread=CreateThread(0,0,OOBHandler,(LPVOID)remoteSocket, 0, &dwThreadId);
    //Create a new thread to process incoming OOB data. "OOBHandler" is a
    //pointer to the OOB data handler.
    else if(strcmp((char *)buffer,"N")==0)
    hThread=CreateThread(0,0,NormalHandler,(LPVOID)remoteSocket, 0, &dwThreadId);
    //Create a new thread to process incoming normal data. "NormalHandler" is
    //a pointer to the normal data handler.
    ...
    }

  3. Για να εξομοιώσετε το μηχανισμό OOB, πρέπει να συγχρονίσετε αυτές τις δύο νημάτων. Σε αυτήν την εφαρμογή δείγματος, χρησιμοποιήστε ένα καθολικό αντικείμενο συμβάντος για να γίνει αυτό. Τοποθετήστε την παρακάτω πρόταση στο επάνω μέρος του αρχείου.
    //Create a manual-reset event object. 
    hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Για να δημιουργήσετε το πρόγραμμα χειρισμού OOB που εκτελείται από ξεχωριστό νήμα. Σε αυτό το πρόγραμμα χειρισμού, μπορείτε να χρησιμοποιήσετε τη συνάρτηση Επιλέξτε να ανιχνεύσουν κατά την άφιξη των δεδομένων. Κατά την άφιξη των δεδομένων, ακολουθήστε τα εξής βήματα:
    1. Για να καλέσετε τη συνάρτηση ResetEvent για να ορίσετε το αντικείμενο συμβάντος hRecvEvent στην κατάσταση μη σηματοδοτηθεί.
      ResetEvent(hRecvEvent);
      Η διαδικασία αυτή εμποδίζει το πρόγραμμα χειρισμού κανονικά δεδομένα που εκτελείται σε ένα άλλο νήμα.
    2. Κλήση της συνάρτησης revc , η ανάγνωση των δεδομένων.
      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Επειδή ενδέχεται να σταλούν περισσότερα δεδομένα από το buffer μπορεί να χωρέσει, καλέστε τη λειτουργία recv ξανά, μαζί με τη σημαία MSG_PEEK , για να προσδιορίσετε αν τα δεδομένα είναι διαθέσιμα του καλωδίου.
      recv(remoteSocket,(char *)&buffer,sizeof(buffer)-1,MSG_PEEK);
      Χρησιμοποιήστε μία από τις ακόλουθες μεθόδους, ανάλογα με το αν υπάρχει δεδομένων σε εκκρεμότητα να διαβαστεί ή όχι:
      • Εάν δεν υπάρχουν δεδομένα είναι σε εκκρεμότητα για ανάγνωση, καλέστε τη λειτουργία την SetEvent για να ορίσετε το αντικείμενο συμβάντος που καθορίζεται στην κατάσταση σηματοδότησης.
        SetEvent(hRecvEvent);
        Όταν το κάνετε αυτό, μπορεί να συνεχίσει το νήμα χειρισμού κανονικά δεδομένα. Το νήμα χειρισμού δεδομένων κανονική αναμένει το αντικείμενο συμβάντος hRecvEvent πριν συνεχίζει το νήμα χειρισμού κανονικά δεδομένα.
      • Εάν δεδομένων είναι ακόμα σε εκκρεμότητα να διαβαστεί, καλέστε τη λειτουργία recv ξανά, για να διαβάσετε τα υπόλοιπα δεδομένα. Στη συνέχεια, αναζητήστε πάλι δεδομένα που εκκρεμούν.
    Επαναλάβετε τα βήματα 4a μέχρι 4c μέχρι να έχει γίνει η ανάγνωση όλων των δεδομένων σε εκκρεμότητα.
  5. Για να δημιουργήσετε το πρόγραμμα χειρισμού κανονικά δεδομένα. Αυτό το πρόγραμμα χειρισμού είναι παρόμοια με το πρόγραμμα χειρισμού δεδομένων OOB, με τη διαφορά ότι ο δείκτης χειρισμού δεδομένων κανονική καλεί τη συνάρτηση WaitForSingleObject όταν ο δείκτης χειρισμού δεδομένων κανονική εντοπίσει ότι έφτασε δεδομένων.
    WaitForSingleObject(hRecvEvent,INFINITE);
    //You can set the interval parameter to a specific value if you do not want
    //the normal data handler to wait for the OOB handler indefinitely when OOB data arrives continuously.
Εμφανίζει το δείγμα κώδικα για την εφαρμογή του διακομιστή, Myserver.cpp

Επιστροφή στην κορυφή

Εμφανίζει το δείγμα κώδικα για την εφαρμογή του προγράμματος-πελάτη, Myclient.cpp

Σημείωση Πρέπει να συμπεριλάβετε μια αναφορά για το αρχείο της βιβλιοθήκης Winsock, Ws2_32.lib, για να κάνετε τον κώδικά σας μεταγλώττιση.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <assert.h>
#include <winsock.h>

main(int argc, char *argv[])
{
int nErr, nSize;
WSADATA wsaData;
SOCKET myOOBSocket = INVALID_SOCKET;
SOCKET myNormalSocket = INVALID_SOCKET;
unsigned short nPort; // Listen for the port number.
struct sockaddr_in remoteIp;

if (argc!=3)
{
printf("TcpDemoC <RemoteIp> <Port>\n");
return 0;
}

// The Init Socket API.
nErr = WSAStartup(MAKEWORD(1,1),&wsaData);
assert(nErr==0);
nPort = (unsigned short)atol(argv[2]);

myOOBSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
assert(myOOBSocket!=INVALID_SOCKET);

myNormalSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
assert(myNormalSocket!=INVALID_SOCKET);

// Connect to the remote address.
remoteIp.sin_family = AF_INET;
remoteIp.sin_port = htons(nPort);;
remoteIp.sin_addr.S_un.S_addr = inet_addr(argv[1]);

nErr = connect(myOOBSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));
if (nErr == SOCKET_ERROR) {
printf("Connect failed because of %lX\n", WSAGetLastError());
goto Cleanup;
}

nSize = send(myOOBSocket,"U",1, 0);
if (nSize == SOCKET_ERROR) {
printf("Send failed because of %lX\n", WSAGetLastError());
goto Cleanup;
}

nErr = connect(myNormalSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));
if (nErr == SOCKET_ERROR) {
int error = WSAGetLastError();
printf("Connect failed because of %lX\n", error);
goto Cleanup;
}

nSize = send(myNormalSocket, "N",1, 0);
if (nSize == SOCKET_ERROR) {
printf("Send failed because of %lX\n", WSAGetLastError());
goto Cleanup;
}

printf("Read for input:\n");
for (;;) {
int ch = _getch();
_putch( ch );
if (ch=='.') {
shutdown(myOOBSocket, 2);
shutdown(myNormalSocket,2);
break;
}
char buf[10];
memset(buf, ch, sizeof(buf));

if (isupper(ch)) {
nSize = send(myOOBSocket, buf, sizeof(buf), 0);
}else{
nSize = send(myNormalSocket, buf, sizeof(buf), 0);
}

if (nSize == SOCKET_ERROR) {
printf("Send failed because of %lX\n", WSAGetLastError());
break;
}
}
Sleep(1000);
Cleanup:
if (myOOBSocket!=INVALID_SOCKET)
closesocket(myOOBSocket);
if (myNormalSocket!=INVALID_SOCKET)
closesocket(myNormalSocket);
WSACleanup();
return 0;
}
Επιστροφή στην κορυφή

Εμφανίζει το δείγμα κώδικα για την εφαρμογή του διακομιστή, Myserver.cpp

Σημείωση Πρέπει να συμπεριλάβετε μια αναφορά για το αρχείο της βιβλιοθήκης Winsock, Ws2_32.lib, για να κάνετε τον κώδικά σας μεταγλώττιση.
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <assert.h>

// Usage: myserver <port>

HANDLE hRecvEvent;

DWORD WINAPI OOBHandler(LPVOID lpParam)
{
int nErr, nRecv_len;
BYTE buffer[10 + 1];
BOOL bClosing=FALSE;
fd_set fdread;

SOCKET remoteSocket=(SOCKET)lpParam;
unsigned long ul=1;
int nRet = ioctlsocket(remoteSocket, FIONBIO, &ul);
if(SOCKET_ERROR==nRet){
printf("Socket() failed: %d\n", WSAGetLastError());
return 1;
}

printf("Waiting");
for (int i=0; i<10; i++) {
printf(".");
Sleep(1000);
}
printf("The OOB handler is ready!\n");

while (!bClosing){
//Always clear the set before you call the select method.
FD_ZERO(&fdread);
//Add sockets to the sets.
FD_SET(remoteSocket, &fdread);
nErr=select(0,&fdread,0,0,0);
if(nErr==SOCKET_ERROR)
{
printf("Select() failed: %d\n",WSAGetLastError());
return 1;
}

if(FD_ISSET(remoteSocket,&fdread)){
ResetEvent(hRecvEvent);
while(1)
{
nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
if(nRecv_len==0){
bClosing=TRUE;
printf("The connection is closed!\n");
break;
}
buffer[nRecv_len] = '\0';
printf("[OOB]: %s\n", buffer);

nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer)-1,MSG_PEEK);
if (nRecv_len==SOCKET_ERROR) {
if(WSAGetLastError()==WSAEWOULDBLOCK)
break;
else
printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());
}
}
SetEvent(hRecvEvent);
}
}
return 0;
}

DWORD WINAPI NormalHandler(LPVOID lpParam)
{
int nErr,nRecv_len;
BYTE buffer[10 + 1];
fd_set fdread;

SOCKET remoteSocket=(SOCKET)lpParam;

printf("Waiting");
for (int i=0; i<10; i++) {
printf("*");
Sleep(1000);
}
printf("Normal handler ready!\n");

while(1) {
//Always clear the set before you call the select method.
FD_ZERO(&fdread);
//Add sockets to the sets.
FD_SET(remoteSocket, &fdread);

nErr=select(0,&fdread,0,0,0);
if(nErr==SOCKET_ERROR){
printf("Select() failed: %d\n",WSAGetLastError());
return 1;
}

if(FD_ISSET(remoteSocket,&fdread)){
WaitForSingleObject(hRecvEvent,INFINITE);
nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);

if (nRecv_len==SOCKET_ERROR) {
printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());
return 1;
}

if(nRecv_len==0){
printf("Connection Closed!\n");
break;
}

buffer[nRecv_len] = '\0';
printf("[Normal]: %s\n", buffer);
}
}
return 0;
}

int main(int argc, char *argv[])
{
WSADATA wsaData;
int nErr;
SOCKET myListener = INVALID_SOCKET;
struct sockaddr_in localIp;
unsigned short nPort;
DWORD dwThreadId;
HANDLE hThread=NULL;

if (argc!=2)
{
printf("MyServer <Port>\n");
return 0;
}
nPort = (unsigned short)atol(argv[1]);

nErr = WSAStartup(MAKEWORD(2,0),&wsaData);
assert(nErr==0);
assert(wsaData.wVersion == MAKEWORD(2,0));

myListener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
assert(myListener!=INVALID_SOCKET);

// Bind the listen socket to any local IP address.
localIp.sin_family = AF_INET;
localIp.sin_port = htons(nPort);;
localIp.sin_addr.S_un.S_addr = INADDR_ANY;

nErr = bind(myListener,(SOCKADDR *)&localIp,sizeof(localIp));
assert(nErr!=SOCKET_ERROR);

nErr = listen(myListener, 5);
assert(nErr==0);

//Create a manual-reset event object.
hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
if (hRecvEvent == NULL)
{
printf("CreateEvent failed with error 0x%lx\n", GetLastError());
return 1;
}

printf("The server is ready!\n");

for (;;) {
struct sockaddr_in remoteIp;
SOCKET remoteSocket = INVALID_SOCKET;
int nAddrLen = sizeof(SOCKADDR);

remoteSocket = accept(myListener, (SOCKADDR *)(&remoteIp), &nAddrLen);
if(remoteSocket == INVALID_SOCKET) {
int error = WSAGetLastError();
printf("Accept() failed. Win32 error is 0x%lx\n", GetLastError());
goto Cleanup;
} else {
printf("Connected from %d.%d.%d.%d:%d\n",
remoteIp.sin_addr.S_un.S_un_b.s_b1,
remoteIp.sin_addr.S_un.S_un_b.s_b2,
remoteIp.sin_addr.S_un.S_un_b.s_b3,
remoteIp.sin_addr.S_un.S_un_b.s_b4,
ntohs(remoteIp.sin_port));

BYTE buffer[1+1];
int nRecv_len=recv(remoteSocket,(char *)&buffer,1,0);
if (nRecv_len==SOCKET_ERROR) {
printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());
return 1;
}

buffer[nRecv_len] = '\0';
if(strcmp((char *)buffer,"U")==0)
hThread=CreateThread(0,0,OOBHandler,(LPVOID)remoteSocket, 0, &dwThreadId);
else if(strcmp((char *)buffer,"N")==0)
hThread=CreateThread(0,0,NormalHandler,(LPVOID)remoteSocket, 0, &dwThreadId);

if(hThread==0){
printf("CreateThread() failed: %d\n",GetLastError());
return 1;
}
CloseHandle(hThread);
}
}
closesocket(myListener);

Cleanup:
WSACleanup();
return 0;
}
Επιστροφή στην κορυφή

Έλεγχος του δείγματος

  1. Σε μια γραμμή εντολών, πληκτρολογήστε Myserver.exe 4444 για να ξεκινήσετε το διακομιστή στη θύρα 4444.

    Η εφαρμογή του διακομιστή εμφανίζει το ακόλουθο μήνυμα και, στη συνέχεια, αναμένει για υπολογιστές-πελάτες:

    Ο διακομιστής είναι έτοιμη!
  2. Σε ένα διαφορετικό παράθυρο γραμμής εντολών, πληκτρολογήστε
    myClient IPAddress 4444 για να ξεκινήσετε τον υπολογιστή-πελάτη.

    Σημείωση Η διεύθυνση IP του συμβόλου κράτησης θέσης είναι ένα σύμβολο κράτησης θέσης για τη διεύθυνση IP του διακομιστή.
  3. Ο διακομιστής εμφανίζει ένα μήνυμα παρόμοιο με το ακόλουθο:

    Waiting.Waiting*..*


    Όταν λαμβάνετε το προηγούμενο μήνυμα, πρέπει να πληκτρολογήσετε aBcDeFgHi του υπολογιστή-πελάτη μέσα σε 10 δευτερόλεπτα πριν ο διακομιστής συνεχίζει.
Μετά από περίπου 10 δευτερόλεπτα, ο διακομιστής εμφανίζει τα εξής:
[OOB]: BBBBBBBBBB
[OOB]: DDDDDDDDDD
[OOB]: FFFFFFFFFF
[OOB]: HHHHHHHHHH

[Κανονικό]: aaaaaaaaaa
[Κανονικό]: cccccccccc
[Κανονικό]: eeeeeeeeee

[Κανονικό]: gggggggggg
[Κανονικό]: iiiiiiiiii
Επιστροφή στην κορυφή

Αναφορές


Για πρόσθετες πληροφορίες, επισκεφθείτε τις ακόλουθες τοποθεσίες της Microsoft Developer Network (MSDN) στο Web:
Εξαρτάται από πρωτόκολλα εκτός εύρους δεδομένων
http://msdn2.microsoft.com/en-us/library/ms740102.aspx

Συναρτήσεις Winsock
http://msdn2.microsoft.com/en-us/library/ms741394.aspx
Για πρόσθετες πληροφορίες, κάντε κλικ στον αριθμό του άρθρου παρακάτω, για να προβάλετε το άρθρο της Γνωσιακής Βάσης της Microsoft:

331756 Ioctlsocket η συνάρτηση δεν μπορεί να εντοπίσει την ενσωματωμένη εκτός εύρους δεδομένων

Επιστροφή στην κορυφή