Слайд 1Разработка сетевых приложений
Судаков А.А.
“Параллельные и распределенные вычисления” Лекция 21
Слайд 2План
Сокеты
Удаленные вызовы процедур
CORBA
Слайд 3Сокеты (socket)
Сокеты – аппаратно и протокольно независимый интерфейс для создания
сетевых приложений
Появились в BSD 4.4
Работа как с файлом
Создать
Открыть (привязать
к адресу, соединить)
Чтение
Запись
Слайд 4
Поддержка всех типов протоколов
сокет
Домен – семейства адресов и протоколов
Тип сокета
- протокол
Слайд 5Домены сокетов
Сокеты могут использоваться для обмена
По сети
В рамках локальной машины
В
рамках кластера
…
Область видимости сокета называется доменом
Домен Интернет INET
Домен Unix
UNIX
…
Слайд 6Семейства протоколов
Домену соответствует набор (семейство) протоколов и адресов
Домен сокетов
Интернет
Семейство протоколов и адресов Интернет (PF_INET, AF_INET)
Протокол TCP
Протокол UDP
Домен
сокетов IPX
семейство протоколов и адресов IPX (PF_IPX,AF_IPX )
Протокол IPX
Протокол SPX
Слайд 7Примеры семейств протоколов
/usr/include/linux/socket.h
/* Supported address families. */
#define AF_UNSPEC
0
#define AF_UNIX 1
/* Unix domain sockets */
#define AF_LOCAL 1 /* POSIX name for AF_UNIX */
#define AF_INET 2 /* Internet IP Protocol */
#define AF_AX25 3 /* Amateur Radio AX.25 */
#define AF_IPX 4 /* Novell IPX */
#define AF_APPLETALK 5 /* AppleTalk DDP */
#define AF_NETROM 6 /* Amateur Radio NET/ROM */
#define AF_BRIDGE 7 /* Multiprotocol bridge */
#define AF_ATMPVC 8 /* ATM PVCs */
#define AF_X25 9 /* Reserved for X.25 project */
#define AF_INET6 10 /* IP version 6 */
#define AF_ROSE 11 /* Amateur Radio X.25 PLP */
#define AF_DECnet 12 /* Reserved for DECnet project */
#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/
#define AF_SECURITY 14 /* Security callback pseudo AF */
#define AF_KEY 15 /* PF_KEY key management API */
#define AF_NETLINK 16
#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */
#define AF_PACKET 17 /* Packet family */
#define AF_ASH 18 /* Ash */
#define AF_ECONET 19 /* Acorn Econet */
Слайд 8Типы сокетов домена Интернет
Сокеты ориентированные на соединения
Потоковый сокет
Гарантированная и надежная
доставка данных
Транспортный протокол TCP или аналогичный
Тип SOCK_STREAM
Сокеты не ориентированные на
соединения
Дейтаграмный сокет
Негарантированная, ненадежная, быстрая доставка данных
Транспортный протокол UDP (или аналогичный)
Тип SOCK_DGRAM
Низкоуровневый сокет
Доступ к низкоуровневым протоколам Интернет
IP
ICMP
IGMP
Заголовкам транспортных протоклов
SOCK_RAW
Доступен только администратору
Слайд 9Функция socket()
Создание сокета заданного домена, семейства и протокола
int socket(int domain,
int type, int protocol);
int fd = socket(PF_INET,SOCK_STREAM, IPPROTO_TCP)
Слайд 10Привязка сокета к сетевому адресу и порту
Большинство протоколов требуют указания
адреса конечной точки коммуникации
IP – сетевой адрес
TCP – порт
Тип и
формат адреса зависит от протокола
Для сокетов разных семейств протоколов и адресов необходимо указывать свои параметры
Слайд 11Функция bind()
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
Sockfd –
сокет, который привязывается
my_addr – указатель на структуру данных адреса, зависящая
от протокола
Addrlen – размер структуры (области памяти)
Слайд 12Формат адреса для семейства протоколов Интернет
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET
*/
u_int16_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
u_int32_t s_addr; /* address in network byte order */
};
Все числовые значения адресов должны быть в «сетевом порядке битов»
Слайд 13Порядок байт сети и локальной машины
Для передачи информации между машинами
все представление данных должно быть одинаковым для всех машин
Разные аппаратные
платформы по разному представляют целые числа
Необходимы функции преобразования сетевого порядка битов в порядок битов машины и наоборот
ntohs() – short от сетевого порядка к порядку хоста
ntohl() - long от сетевого порядка к порядку хоста
htons() - short от порядка хоста к сетевому порядку
htonl() - long от порядка хоста к сетевому порядку
Слайд 14Пример привязки адреса
struct sockaddr_in addr;
unsigned long ip_addr_host = 0x0A190511;
//10.25.5.11;
unsigned long ip_addr_net = htonl(ip_addr_host );
// 0x1105190A
unsigned short tcp_port_host=22;
// 0x0016
unsigned
short tcp_port_net=htons(tcp_port_host);
//0x1600
addr.sin_family = AF_INET;
addr.sin_port = tcp_port_net;
addr.s_addr = ip_addr_net;
bind(sock_fd, &addr, sizeof(addr));
Слайд 15Возможности получения адресов
IP адрес машины
В сетевом порядке
Любой адрес машины
Константа INADDR_ANY
Преобразование строки в ip адрес
Функция inet_addr()
unsigned long xaddr = inet_addr
(“10.25.0.11”);
Служба доменных имен
Преобразование имени машины в ip адрес
Слайд 16Использование службы доменных имен
для получения ip адреса
struct sockaddr_in addr;
struct hostent
*gethostbyname(const char *name);
struct hostent {
char *h_name; /* official name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* host address type */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses */
};
Пример
struct hostent *hp = gethostbyname(“cluster.univ.kiev.ua”);
memcpy ((char *) &addr.sin_addr, (char *) hp->h_addr, hp->h_length);
Слайд 17Режимы сокетов
Несоединенный сокет
Соединенный сокет
Сокет может отправлять данные тому сокету, с
которым он соединен
Обязательно для передачи данных через сокеты ориентированные на
соединение
Режим прослушивания
Сокет ожидает приема соединений
Обязательно для серверных сокетов, ориентированных на соединение
Режим приема соединения
Сокет в режиме прослушивания возвращает соединенный с клиентом сокет
Используется серверными сокетами
Слайд 18Соединение сокетов
Соединение – установление виртуального канала между двумя сокетами
Выполняет клиент
Для
протоколов ориентированных на соединение – обязательно
После соединения можно передавать и
принимать данные из сокета
Слайд 19Функция connect()
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
Соединяет
указанный сокет с указанным адресом
sid – сокет
Addr – заполненная структура
адреса
len – размер структуры
connect(sid,(sockaddr*)&addr,len);
Слайд 20Серверный сокет в режиме прослушивания (LISTEN)
Сервер постоянно «слушает» на сетевые
соединения
Используется специальный режим сокета LISTEN
Сокету должен быть назначен адрес
Должна быть
вызвана функция listen()
int listen(int socket_fd, int max_backlog)
socket_fd – сокет, который переводится в режим прослушивания
max_backlog – максимальное количество входных соединений, которые ожидают на прием
Слайд 21Сокет в режиме приема входящих соединений (accept)
Если есть входящие соединения,
то серверный сокет должен их принять
После приема возвращается новый сокет,
соединенный с клиентским
Серверный сокет продолжает слушать
Фунция accept()
int new_sock = accept(int s, struct sockaddr *addr, socklen_t *addrlen);
s – сокет, на которое поступило соединение
addr – адрес и протокол партнера по соединению
addrlen – длина адреса
Слайд 22Прием и передача информации
Через два соединенных сокета возможен прием и
передача данных в обоих направлениях
Прием – функция read() или recv()
ssize_t
read(int fd, void *buf, size_t count);
fd – дескриптор сокета
buf – указатель начала данных в памяти
count – количество байт данных для передачи
Передача данных – write() recv()
ssize_t write(int fd, const void *buf, size_t count);
fd – дескриптор сокета
buf – указатель начала области памяти, куда писать данные
count – количество байт данных для приема
Слайд 23Диаграмма работы с сокетами TCP
Сервер
socket()
bind()
listen()
accept()
Клиент
socket()
connect()
возвращаем
соединенный сокет
возвращаем
соединенный сокет
read() write()
Send() recv()
read() write()
Send()
recv()
Слайд 24Класс sock_1
Разработан для упрощения работы с сокетами
Имеет функции с тем
же названием, но более простые в использовании
Слайд 25Пример сервера
#include "sock_1.h"
#include
using namespace std;
int main(){
sock_1 sock_listen(PF_INET, SOCK_STREAM);
try {
if(sock_listen.bind(NULL,34567)<0) throw "bind error";
int fd;
if((fd = sock_listen.accept(NULL,NULL)) < 0 ) throw "accept error";
sock_1 sock_connected(fd);
char message[4096];
int len = sock_connected.read(message,4096);
cout << "CLIENT SENT "< sock_connected.write(message,len);
} catch(char * er){
cerr < return -1;
}
return 0;
}
Слайд 26Пример клиента
#include "sock_1.h"
#include
using namespace std;
int main(){
sock_1 connect_sock(PF_INET,SOCK_STREAM);
try {
if(connect_sock.connect("cluster.univ.kiev.ua",34567)<0) throw "connect";
char message[4096]="HI server";
connect_sock.write(message,strlen(message));
int len = connect_sock.read(message,4096);
cerr << "server send " << message <<"of length "< }catch (char* er) {
cerr < return -1;
}
return 0;
}
Слайд 27Пример выполнения
[saa@cluster socket]$ g++ ./client.cpp ./sock_1.cpp -o client
[saa@cluster socket]$ ./client
server
send HI serverof length 9
[saa@cluster socket]$ g++ ./server.cpp ./sock_1.cpp -o
server
[saa@cluster socket]$ ./server
CLIENT SENT HI server of length 9
Слайд 28Синхронное и асинхронное выполнение
Функции работы с сокетами могут блокироваться
connect()
accept()
read()
write()
Процесс останавливается
в ожидании события
Для предотвращения ожидания возможны следующие варианты
Проверка наличия данных
в сокете
Неблокирующий режим
Асинхронный ввод-вывод
Слайд 29Проверка наличия данных
Функция select()
int select(int n, fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
Проверка возможности ввода-вывода для дескрипторов, указанных
в аргументах
readfds - на возможность чтения или успешность accept
writefds - на возможность записи или успешность connect
Exceptfds - на наличие ошибок
N - максимальный номер дескриптора
Timeout – максимальное время ожидания
Слайд 30Удаленные вызовы процедур
Надстройка над сокетами
Позволяют просто
передавать сложные структуры данных
на удаленную машину
Выполнять с ними действия
Возвращать результат
Это выглядит как вызов
процедуры на удаленной машине
Слайд 31Extended data representation
Сериализация данных
Независимость от аппаратной платформы и операционной системы
Предоставляются
функции для стандартных типов данных
xdr_int – для целочисленных типов
xdr_opaque –
для произвольного массива байт
xdr_string – для строки символов
Слайд 32Использование компилятора RPCGEN
Создание описания интерфейсов
Компиляция описания интерфейсов
Создаются файлы клиентов и
серверов на языке С
Создание тела удаленных процедур
Создание клиентских вызовов
Компиляция клиента
и сервера
Слайд 33Пример описания интерфейсов
program TESTPROG {
version TESTVER
{
string PRINT
(string) = 1;
} = 1;
} = 0x22222222;
[saa@cluster rpc]$ rpcgen test.x
[saa@cluster rpc]$ ls
test.h test_svc.c
test_clnt.c test.x
Слайд 34Создание тела процедуры
#include "test.h"
#include
char* responce = "HI! client";
char** print_1_svc(char**
arg,struct svc_req * r){
printf("client sent: %s\n",*arg);
return &responce;
}
Слайд 35Создание клиента
#include "test.h"
#include
int main (int argc, char* argv[]){
CLIENT* cl;
char** responce;
cl = clnt_create(argv[1],TESTPROG,TESTVER,"tcp");
if(!cl) {
clnt_pcreateerror("");
return -1;
}
responce = print_1(&argv[2],cl);
if(!responce) {
clnt_perror(cl,"");
return -1;
}
printf("Server respond with %s\n",*responce);
return 0;
}
Слайд 36Компиляция клиента и сервера
[saa@cluster rpc]$ gcc ./print_client.c test_clnt.c -o client
[saa@cluster
rpc]$ gcc ./test_svc.c test_print.c -o server
Слайд 37Пример работы
Клиент:
[saa@cluster rpc]$ ./client cluster "Hi server"
Server respond with HI!
Client
Сервер:
[saa@cluster rpc]$ ./server
client sent: Hi server
Слайд 38CORBA
Надстройка над сокетами
Объектно-ориентированные RPC
Упрощается создание распределенных объектно-ориентированных приложений
Слайд 39Процесс создания распределенной программы
Создается описание интерфейсов
Описание интерфейсов компилируется в язык
высокого уровня
Создается тело функции сервера
Создается сервер
Создается клиент
Слайд 40Пример – описание интерфейса
module TestModule
{
interface TestInterface
{
string
print(in string mes);
};
};
[saa@cluster 1]$ orbit-idl-2 --skeleton-impl test.idl
orbit-idl-2 2.8.2 compiling
mode, show preprocessor errors, passes: stubs skels common headers imodule
[saa@cluster 1]$ ls
test-common.c test.h test.idl test-skelimpl.c test-skels.c test-stubs.c
[saa@cluster 1]$
Слайд 41Создание тела функции (test-skelimpl.c)
static CORBA_string
impl_TestModule_TestInterface_print(impl_POA_test_test * servant,
const CORBA_char
* mes, CORBA_Environment * ev)
{
CORBA_string retval;
/* ------ insert method code here ------ */
printf("client sent: %s\n",mes);
retval = CORBA_string_alloc(512);
sprintf (retval,"Hi client");
/* ------ ---------- end ------------ ------ */
return retval;
}
Слайд 42Создание сервера
Инициализация библиотеки CORBA
Создание ORB
Создание адаптера объектов
Создание объектов
Активизация сервера
Получение ссылок
на объект
Запуск сервера
Слайд 43Пример сервера (test-skelimpl.c)
int main (int argc, char* argv[]){
PortableServer_POA poa;
TestModule_TestInterface server = CORBA_OBJECT_NIL;
CORBA_ORB orb = CORBA_OBJECT_NIL;
CORBA_Environment ev;
gchar *objref=NULL;
CORBA_char filename[] = "test_service.ior";
FILE* file = NULL;
CORBA_exception_init(&ev);
orb=CORBA_ORB_init(&argc,argv,"orbit-local-orb",&ev);
poa= (PortableServer_POA) CORBA_ORB_resolve_initial_references(orb,"RootPOA",&ev);
server = impl_TestModule_TestInterface__create (poa, &ev);
PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(poa, &ev),&ev);
objref= CORBA_ORB_object_to_string (orb, server, &ev);
if ((file=fopen(filename, "w"))==NULL)
g_error ("could not open '%s'\n", filename);
fprintf(file, "%s",objref);
fclose (file);
free(objref);
CORBA_ORB_run(orb,&ev);
CORBA_Object_release(server,&ev);
CORBA_ORB_shutdown(orb,CORBA_FALSE,&ev);
return 0;
}
Слайд 44Создание клиента (test_client.c)
Инициализация библиотеки CORBA
Инициализация брокера
Получение ссылки на объект
Вызов функций
Слайд 45Пример клиента
#include
#include "test.h"
int main(int argc, char* argv[]){
CORBA_ORB orb=CORBA_OBJECT_NIL;
CORBA_Environment ev;
TestModule_TestInterface service = CORBA_OBJECT_NIL;
CORBA_char filename[]="test_service.ior";
CORBA_exception_init(&ev);
orb=CORBA_ORB_init(&argc,argv,"orbit-local-orb",&ev);
FILE *file = NULL;
if ((file=fopen(filename, "r"))==NULL)
g_error ("could not open %s\n", filename);
gchar *objref=NULL;
fscanf (file, "%as", &objref);
service = (TestModule_TestInterface) CORBA_ORB_string_to_object (orb,
objref,
&ev);
free (objref);
char* mes = TestModule_TestInterface_print(service,argv[1],&ev) ;
printf("server sent: %s\n",mes);
return 0;
}
Слайд 46Компиляция сервера и клиента
[saa@cluster 1]$ gcc `orbit2-config --cflags` `orbit2-config --libs`
test-stubs.c test_client.c test-skels.c test-common.c -o client
[saa@cluster 1]$ gcc `orbit2-config --cflags`
`orbit2-config --libs` test-skelimpl.c test-skels.c test-common.c -o server
Слайд 47Запуск клиента и сервера
[saa@cluster 1]$ ./server
client sent: Hi server!
[saa@cluster 1]$
./client 'Hi server!'
server sent: Hi client