Знание операционных систем windows и linux сетевых протоколов

Отличия сетевых вызовов Windows и Linux

image

Во многом совместимые на уровне исходных кодов модели сокетов от Berkeley и Microsoft, на практике оказываются не такими уж кросплатформенными.

Рассмотрим некоторые хитрые различия в их реализации, которые обнаружились при написании кросплатформенного RPC для перенаправления сетевых вызовов некоторого процесса в одной ОС на другую ОС.

Дескриптор сокета на BSD ничем не отличается от дескриптора файла, а значит, некоторые системные вызовы принимают одновременно описатели и сокетов и файлов (например, такие-вот «редко» используемые вызовы, как close(), fcntl() и ioctl()).
Еще есть побочный эффект, проявляющий себя в довольно подлых ситуациях, заключающийся в том, что в системах с поддержкой модели Berkeley числовое значение описателя сокета — обычно маленькое число (меньше 100), и подряд создающиеся дескрипторы различаются на 1. В модели Microsoft такой описатель сразу больше 200 (примерно), а подряд создающиеся описатели различаются на sizeof(SOCKET).

  • BSD: Вызовы возвращают -1, устанавливается глобальная перменная errno.
  • Win: Вызовы возвращают -1 (макрос SOCKET_ERROR), статус получаем с помощью WSAGetLastError().

Создание сокетов:

socket(int af, int type, int protocol);

Константы для первого аргумента имеют абсолютно разные значения на BSD и Windows. Для второго пока совпадают.

getsockopt(int sockfd, int level, int option_name, void *option_value, socklen_t *option_len);
setsockopt(int sockfd, int level, int option_name, void const *option_value, socklen_t option_len)

Работа с DNS

struct addrinfo
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
>;

recv(int sockfd, void *buffer, size_t length, int flags);
recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *from, socklen_t *fromlen);
send(int sockfd, void const *buffer, size_t length, int flags);
sendto(int sockfd, void const *buffer, size_t length, int flags, struct sockaddr const *to, socklen_t tolen);

Читайте также:  Звезда базовая топология компьютерной сети в которой все компьютеры

    BSD: poll(struct pollfd *fds, nfds_t nfds, int timeout);

struct pollfd
int fd;
short events;
short revents;
>;

    BSD: select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);

typedef struct
long fds_bits[FD_SETSIZE / 8 * sizeof(long)];
> fd_set;

Для BSD помещение некоторого сокета в некоторое множество заключается во взведении в последнем такого бита, порядковый номер которого численно равен дескриптору сокета. FD_SETSIZE обычно равно 1024. Первый аргумент select() представляет собой максимальное числовое значение дескриптора сокета, входящего в любое из трех множеств плюс один. Учитывая, что установка бита в массиве fds_bits производится исключительно без проверки диапазона, становится ясно, что при значении дескриптора сокета >= FD_SETSIZE поведение программы неопределено. Такая, несколько ненадежная реализация select — пережиток скупых на память компьютеров. Кстати, вот в каком случае важно непрямое преобразование int -> SOCKET и обратно.

Для Windows помещение некоторого сокета в некоторое множество заключается во вставке его в массив fd_array по индексу fd_count и дальнейшем увеличении последнего. FD_SETSIZE обычно равно 64. При этом, первый аргумент select() игнорируется вовсе.

Источник

Оцените статью
Adblock
detector