1.1.2. Създаване и инициализация на сокет
След като интерфейсът WindowsSockets бъде инициализиран, приложението трябва да създаде един или повече гнезда, които ще се използват за прехвърляне на данни.
Сокет се създава с помощта на функцията socket, която има следния прототип:
SOCKET socket(int af, int тип, int протокол);
Параметрите тип и протокол определят съответно типа сокет и протокола, който ще се използва за този сокет.
Можете да посочите сокети от следните два типа:
Описание на типа гнездо
SOCK_STREAM Сокетът ще се използва за прехвърляне на данни през комуникационен канал, използващ TCP протокола.
SOCK_DGRAM Прехвърлянето на данни ще се извършва без създаване на комуникационни канали чрез UDP дейтаграмен протокол
Що се отнася до параметъра на протокола, можете да посочите нулева стойност за него. Ако е успешна, функцията за сокет връща манипулатор, който трябва да се използва за извършване на всички операции на дадения сокет. Ако възникне грешка, тази функция връща INVALID_SOCKET. За да анализирате причината за грешката, можете да извикате функцията WSAGetLastError, която в този случай може да върне един от следните кодове за грешка:
Описание на кода на грешка
WSANOTINIT1ALISED Интерфейсът на WindowsSockets не е инициализиран с функцията WSAStanup
WSAENETDOWN Грешка в мрежовия софтуер
WSAEINPROGRESS Функцията за блокиране на интерфейса на WindowsSockets е в ход
WSAEMFILE Всички безплатни дескриптори са използвани.
WSAENOBUFS Няма памет за създаване на буфер
WSAEPROTONOSUPPORT Посочен невалиден протокол
WSAEPROTOTYPE Посоченият протокол не е съвместим с дадения тип сокет.
По-долу е даден кодов фрагмент, който създава сокет за пренос на данни с помощта на TCP протокола:
srv_socket = сокет (AF_INET, SOCK_STREAM, 0);
MessageBox(NULL, "Грешка на сокета", "Грешка", MB_OK);
1.1.2.2. Изтриване на сокет
За да освободи ресурси, приложението трябва да затвори сокети, от които вече не се нуждае, като извика функцията closesocket:
int closesocket(SOCKET socket);
Кодовете за грешки за тази функция са изброени по-долу:
Описание на кода на грешка
WSANOTINIT1ALISED Трябва да извикате функцията WSAStartup, преди да използвате функцията closesocket.
WSAENETDOWN Грешка в мрежата
WSAENOTSOCK Манипулаторът, посочен в параметъра, не е сокет.
WSAEINPROGRESS Функцията за блокиране на интерфейса на WindowsSockets е в ход
WSAAINTR Функцията беше отменена с помощта на функцията WSACancelBlockingCall.
1.1.2.3. Опции на гнездото
Параметрите на гнездото трябва да бъдат зададени преди употреба.
За да направим това, трябва да подготвим структура от тип sockaddr, чиято дефиниция е показана по-долу:
typedef struct sockaddr SOCKADDR;
typedef struct sockaddr *PSOCKADDR;
typedef struct sockaddr FAR *LPSOCKADDR;
struct in_addr sin_addr;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr_in *PSOCKADDR_IN;
typedef struct sockaddr_in FAR *LPSOCKADDR_IN;
Полето sin_port указва номера на порта, който ще се използва за прехвърляне на данни. Портът е просто идентификатор за програмата, която комуникира в мрежата. Няколко програми могат да работят на един и същ възел едновременно, като използват различни портове.
Универсалният мрежов формат на данни е удобен за организиране на глобални мрежи, тъй като в възлите на такава мрежа могат да се използват компютри с различни архитектури.
За извършване на преобразувания от обикновен формат в мрежов формат и обратно къмИнтерфейсът WindowsSockets предоставя специален набор от функции. По-специално, за да попълните полето sin_port, трябва да използвате функцията htons, която преобразува 16-битови данни от формата на Intel в мрежовия формат. Следващото показва какполетоsin_port се инициализира в приложението SERVER, описано по-долу:
#define SERV_PORT 5000 srv_address.sin_port = htons(SERV_PORT);
Да се върнем към структурата sockaddr_in. Полето sin_addr на тази структура от своя страна е структура in_addr
#дефинирайте s_addr S_un.S_addr
#define s_host S_un.S..un_b.s_b2
#define s_net S_un.S_un_b.s_bl
#define s_imp S_un.S_un_w.s_w2
#define s_impno S_un.S_un_b.s_b4
#define s_lh S_un.S_un_b.s_b3
В случай на грешка, функцията връща INADDR_NONE, което може да се използва за проверка.
char FAR *inet_ntoa(struct in_addr in);
При грешка тази функция връща NULL.
MessageBox(NULL, "gethostbyname Error", "Error", MB_OK);
Функцията gethostbyname връща нула при грешка. Можете обаче да разберете причината за грешката, като разгледате кода за връщане на функцията WSAGetLastError.
Ако посоченият хост е намерен в DNS базата данни или във файла HOSTS, функцията gethostbyname връща указател към структурата на хост, описана по-долу:
char FAR * h_name; // име на възел
char FAR *FAR *h_псевдони; // списък с алтернативни имена
typedef struct hostent *PHOSTENT;
typedef struct hostent FAR *LPHOSTENT;
int bind(SOCKET sock, const struct sockaddr FAR *addr, int namelen);
Параметърът sock трябва да съдържа манипулатор на сокета, създаден от socket. Полето addr трябва да съдържа указател към подготвената SOCKADDR структура, а полето namelen трябва да съдържа размера на тази структура.структури.
Функцията за свързване връща SOCKET_ERROR при грешка. Допълнителен анализ на причините за грешката трябва да се извърши с помощта на функцията WSAGetLastError.Възможните кодове на грешка са изброени по-долу:
Описание на кода на грешка
WSANOTINITIALISED Трябва да извикате функцията WSAStanup, преди да използвате функцията.
WSAENETDOWN Грешка в мрежата
WSAEFAULT namelen е по-малко от размера на sockaddr
WSAEINPROGRESS Функцията за блокиране на интерфейса на WindowsSockets е в ход
WSAENOBUFS Установени са твърде много връзки
WSAENOTSOCK Манипулаторът, посочен в параметъра, не е сокет.
Пример за извикване на функцията за свързване е показан по-долу:
if(bind(srv_socket, (LPSOCKADDR)&srv_address, sizeof(srv_address)) == SOCKET_ERROR)
MessageBox(NULL, "грешка при свързване", "Грешка", MB_OK);