Это архив сайта coldflame.by.ru, он не обновлялся с 2007 года. Мой современный сайт тут: http://leonid.shevtsov.me.
Домой! Обо мне Специально для РИ-06-1 Разнообразное... барахло, короче :) Программы и прочее Статьи и переводы Блог SmartDaemon

Отличия Winsock от Unix Sockets

Сразу скажу: это не полноценное описание всех отличий виндовских сокетов от юниксовых, это всего лишь описание того, как использовать руководство Beej'а под Windows.

Файлы заголовков и бибилиотеки

Windows заменяет всю кучу заголовков на один, но большой winsock2.h, а НЕ winsock.h, как пишет Beej. Т.е. сработает и тот, и другой, но современная версия Winsock (2.2) реализована заголовком winsock2.h. И не надо спорить с Microsoft.

Также к проекту, использующему WinSock, надо подключить библиотеку ws2_32.lib. В Visual C++ можно это сделать прямо из кода, директивой #pragma. Рекомендую!

Итак, вместо всех заголовков Berkeley Sockets нужно писать:

#pragma comment(lib,"ws2_32.lib")
#include <winsock2.h>

Инициализация и завершение WinSock

Библиотеку WinSock надо отдельно инициализировать и, соответственно, завершать. Это можно делать в любом месте кода, но до (и, соответственно, после) всех операций с WinSock. Для этого есть две функции: WSAStartup() и WSACleanup(). В первой нужно указать, какая версия WinSock нам нужна. Рекомендуется, не особо задумываясь, просить версию 2.2.

...
//самое начало кода
WSADATA wd;
if (
    (WSAStartup(MAKEWORD( 2, 2 ),&wd)!=0)||
    (wd.wVersion!=2)||
    (wd.wHighVersion!=2))
{
    //WinSock 2.2 не поддерживается или ошибка инициализации... увы
    //выходим
}
...
...
//вся программа...
...
...
//самый конец кода
WSACleanup();
...

В структуру WSADATA возвращается всякая бесполезная информация о WinSock, можешь посмотреть в MSDN, если тебе интересно. После вызова WSAStartup можно работать с сокетами так же, как в Unix... то есть, почти так же. Читай дальше!

Тип сокетов

Открою страшный секрет: WinSock только прикидывается, что это Unix Sockets! На самом деле сокеты WinSock не имеют никакого отношения к дескрипторам файлов.

Поэтому сокеты в Виндовс имеют тип SOCKET. Тип SOCKET равен unsigned int, ха-ха, Билли Гейтсу надо было отличиться. Поэтому в вызовах socket() и accept() при ошибке возвращается константа INVALID_SOCKET, а не -1. Кстати, INVALID_SOCKET тоже равно -1, т.е. ~0. Но в Windows все через, эээ, заднепроходное отверстие. :)

SOCKET s;
s=socket(PF_INET,SOCK_STREAM,0);
if (s==INVALID_SOCKET) {
    //ошибка
}

Коды ошибок

Вместо кода -1 используется константа SOCKET_ERROR. Хоть одна умная вещь... замена числа символической константой улучшает читабельность кода. Можно, впрочем, и не использовать эту константу - она все равно равна -1.

Механизм возвращения ошибок через errno в Windows не используется. Вместо этого нужно использовать винсоковскую функцию WSAGetLastError. Символические имена ошибок изменены - в начало дописано WSA, например, вместо EWOULDBLOCK нужно писать WSAEWOULDBLOCK.

if (recv(...)==SOCKET_ERROR) {
    if (WSAGetLastError() == WSAEWOULDBLOCK)
    {
        //обрабатываем ошибку
    }
}

Впрочем, никто не мешает использовать define'ы чтобы обеспечить портабельность:

#define errno WSAGetLastError()
#define EWOULDBLOCK WSAEWOULDBLOCK
...
...
if (recv(...)==-1) 
    if (errno == EWOULDBLOCK)
    {
        //обрабатываем ошибку
    }
}

Функция perror() НЕ сообщает описания ошибок WinSock. И ей нет замены. Увы.

closesocket()

Вместо close() нужно применять closesocket().

После этих небольших изменений ты должен применять код руководства без всяких проблем. За исключением функции fork(); смотри мои портированные примеры.

Подробнее

В Winsock FAQ содержится гораздо более подробное рассмотрение WinSock'а, в том числе и его отличий от Berkeley Sockets.