Главная

Популярная публикация

Научная публикация

Случайная публикация

Обратная связь

ТОР 5 статей:

Методические подходы к анализу финансового состояния предприятия

Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века

Ценовые и неценовые факторы

Характеристика шлифовальных кругов и ее маркировка

Служебные части речи. Предлог. Союз. Частицы

КАТЕГОРИИ:






Использование интерфейса сокетов в операционной системе MS Windows




 

В ОС Windows функции интерфейса сокетов не являются системными вызовами и реализованы в дополнительной динамической библиотеке Winsock.dll. Эта библиотека (версия 1) создана большим коллективом разработчиков из различных организаций. Она максимально приближена к оригинальной библиотеке сокетов разработки Калифорнийского университета, настолько, насколько это вообще возможно. Версия 2 библиотеки Winsock разработана уже корпорацией Microsoft и мало интересна, хотя и имеет намного больший объем. Там развиты средства обеспечения работы в различных протокольных стеках и добавлен ряд вспомогательных функций, прежде всего – функции локального межпроцессного взаимодействия с помощью сигналов, отсутствующие в Windows.

Для использования библиотека Winsock должна быть динамически подключена к выполняющемуся процессу, для чего может быть использован следующий фрагмент кода:

 

#include <winsock.h>

#define WINSOCK_VERSION 0x0101

WSADATA wsaData;

 

if (WSAStartup(WINSOCK_VERSION,&wsaData)) {

printf(NULL,"Не та версия winsock.dll!!!\n");

exit(-1);

}

 

Поскольку функции библиотеки языка С остались неизменными, пришлось:

1. Изменить тип дескрипторов сокетов. Вместо типа int используется тип SOCKET, отображаемый на unsigned int. Соответственно, при проверке, успешно ли создан сокет, возвращенный функцией socket() дескриптор бессмысленно проверять на знак, как это обычно делают для сокетов Беркли. Необходимо этот дескриптор сравнивать на равенство с константой INVALID_SOCKET.

2. В связи с этим изменением пришлось изменить реализацию функции select(), позволяющую реализовать ожидание на массиве дескрипторов.

3. Отказаться от использования функций read(), write(), close(), ioctl(), которые могут работать только с файлами. Вместо них следует использовать функции recv(), send() и вновь введенные функции int closesocket(SOCKET) и int ioctlsocket(SOCKET,long,u_long*) соответственно.

4. Отказаться от использования глобальных переменных ошибок errno и h_errno и ввести дополнительные функции для получения кодов ошибок.

5. Для проверки наличия ошибок значения, возвращаемые большинством функций, следует сравнивать на равенство с константой SOCKET_ERROR.

Кроме того, могут наблюдаться проблемы с использованием блокирующих операций. В остальном же интерфейс сокетов для Windows ничем не отличается от оригинального интерфейса разработки Калифорнийского университета.

 

2. СЕТЕВЫЕ ПРОГРАММЫ В АРХИТЕКТУРЕ «КЛИЕНТ-СЕРВЕР»

 

В качестве примера использования интерфейса сокетов рассмотрим программу, работающую под управлением POSIX-совместимой операционной системы, демонстрирующую взаимодействие клиента и сервера с использованием потоковых сокетов.

Для взаимодействия будем использовать жестко заданный в коде программы номер порта, который объявим в заголовочном файле:

 

#include <stdio.h>

#include <string.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#define PORT 6259 /* номер порта */

 

Будем также передавать между клиентом и сервером текстовые сообщения заданной длины, и для обеспечения передачи данных именно требуемого объема используем буферные функции с циклами добора данных:

 

/* запись в сокет буфера, состоящего из пос байт */

int writes(

register int sock, /* дескриптор сокета */

register char *pbuf, /* буфер */

register int noc) /* число записываемых байт */

{

int nreste, necrit;

nreste = noc;

while (nreste > 0) {

necrit = write(sock, pbuf, nreste);

if (necrit < 0) return(necrit);

nreste -= necrit;

pbuf += necrit;

}

return(noc-nreste);

}

/* считывание в буфер пос байт из сокета */

int reads(

register int sock, /* дескриптор сокета */

register char *pbuf, /* буфер */

register int noc) /* число считываемых байт */

{

int nreste, nlit;

 

nreste = noc;

while (nreste > 0) {

nlit = read(sock, pbuf, nreste);

if (nlit < 0) return(nlit);

else if (nlit == 0) break;

nreste -= nlit;

pbuf += nlit;

}

return(noc-nreste);

}

 

Собственно передачу текстовых сообщений будем осуществлять следующим образом:

1. Определяется длина передаваемой строки.

2. Длина переводится в сетевой формат и передается.

3. Передается сама строка.

4. В качестве признака конца сеанса передается нулевая длина строки.

Клиентская часть программы получается следующей:

 

main(void)

{

/*вызов функции, выполняющей специальную обpаботку */

clientipc();

exit(0);

}

/*функция, pеализующая специальную обpаботку */

clientipc()

{

int sock; /* дескриптор сокета */

struct sockaddr_in server; /* адрес сервера */

struct in_addr *srv;

unsigned long addr_s;

/* создание сокета */

sock = socket(PF_INET, SOCK_STREAM, 0);

/* формирование сокет-адреса */

bzero(&server, sizeof(server));

server.sin_family = PF_INET;

srv=&(server.sin_addr);

addr_s = inet_addr("127.0.0.1");

(*srv).s_addr = addr_s;

server.sin_port = htons(PORT);

/* соединение с сервером */

connect(sock, (struct sockaddr *) &(server),sizeof(server));

printf("connect to server\n");

/* вызов службы */

client(sock);

/* закрытие соединения */

close(sock);

}

/* функция приема-передачи */

client(sock)

int sock; /* дескриптор сокета */

{

int lbuf,lbufres; /* целое число в сетевом формате */

char msg[]="Hello";

int ret;

/* начнем с пересылки размера буфера; обратите внимание на

то, что число надо передать в сетевом формате */

lbuf=strlen(msg)+1;

lbufres = htons(lbuf);

ret = writes(sock, &lbufres, sizeof(lbufres));

ret = writes(sock, msg, lbuf);

lbuf=0;

lbufres = htons(lbuf);

ret = writes(sock, &lbufres, sizeof(lbufres));

}

 

Создается сокет, формируется сокет-адрес(IP-адрес 127.0.0.1, порт 6259), сокет связывается с этим адресом, устанавливается соединение с сервером, по этому соединению передается информация в соответствие с описанным выше протоколом, соединение закрывается.

Серверная часть программы строится аналогично:

 

main(void)

{

/*вызов функции, выполняющей специальную обpаботку */

serveripc();

exit(0);

}

/*функция, pеализующая специальную обpаботку */

serveripc()

{

int sock; /* дескриптор сокета */

int nsock; /* дескриптор сокета */

int ret; /* возвращаемое значение */

struct sockaddr_in server; /* адрес сервера */

/* создание сокета */

sock = socket(PF_INET, SOCK_STREAM, 0);

/* назначение адреса сокету */

bzero(&server, sizeof(server));

server.sin_family = PF_INET;

server.sin_addr.s_addr = INADDR_ANY;

server.sin_port = htons(PORT);

bind(sock, (struct sockaddr *) &server, sizeof(server));

/* переход к прослушиванию приходящих связей */

listen(sock, 5);

/* цикл по запросам на соединение */

for (;;) {

nsock = accept(sock, (struct sockaddr *) 0, (int *) 0);

/* обращение к циклу чтение-запись */

serv(nsock);

/* закрытие текущей связи */

close (nsock);

}

}

/*функция пpиема-пеpедачи */

serv(

int sock) /* дескриптор сокета */

{

int lbufres; /* целое число в формате сети */

int lbuf;

char buf[1024];

int ret;

while(1)

{

ret = reads(sock, &lbufres, sizeof(lbufres));

if (ret==0) exit(0);

lbuf=ntohs(lbufres);

if (lbuf>1024) exit(0);

if (lbuf==0) break;

ret = reads(sock, &buf, lbuf);

printf("Server: message=%s\n",buf);

}

}

 

Создается сокет, формируется локальный сервисный сокет-адрес(порт 6259), сокет связывается с этим адресом, переводится в режим прослушивания входящих соединений, ожидается и принимается соединение с клиентом, по этому соединению принимается информация в соответствие с описанным выше протоколом, соединение закрывается, переходим к ожиданию следующего запроса на соединение.

 






Не нашли, что искали? Воспользуйтесь поиском:

vikidalka.ru - 2015-2024 год. Все права принадлежат их авторам! Нарушение авторских прав | Нарушение персональных данных