Читайте также:
|
|
Первый системный вызов - socket().
socket(< домен, к которому относится socket >, < тип сокета >, < номер протокола >)
Обладает тремя параметрами:
1) домен, к которому относится сокет (указывается с помощью символьной константы PF_UNIX/PF_LOCAL, PF_INET). Мы будет изучать два: первый — IP-сокеты или интернет-сокеты, второй - Unix- или локальные сокеты. Первые служат для связи программ через интернет, вторые - для связи программ на одном компьютере.
2)тип сокета: SOCK_STREAM ориентирован на соединение, SOCK_DGRAM. Первый обладает следующими свойствами: пакеты не теряются, приходят в том порядке,в котором были посланы, сообщения никогда не дублируются. В SOCK_DGRAM все сообщения передаются независимо.
3) номер протокола - ранее полагали, что это важно, но на данный момент используются только первые два (т.к. их достаточно для определения сокета), в этом месте всегда ставится 0.
После выполнения всех действий, функция socket возвращает номер сокета, который можно использовать в операциях ввода-вывода (то есть который может быть использован в read или write).
bind() связывает между собой адрес сокета и сокет.
bind(< номер сокета >, < структура, соответствующая домену >, < длина этой структуры >)
Для адреса используется специальная структура данных: sockaddr. Эта структура данных обладает двумя полями: длина и домен, для которого этот адрес сокета указывается. Остальные поля структуры зависят от того,к какому домену относится этот сокет. Для IP-сокетов это одни поля, для юниксовых - другие, там указываются имя файла. Соответственно, чтобы задать адрес сокета для айпи сокетов надо использовать структуру данных sockaddr_in, а для юникосовых - sockaddr-un. Всегда используется модификация sockaddr,в чистом виде она не используется. Чтобы посмотреть,какие поля содержатся в структуре sockaddr_in и sockaddr-un надо использвать man 4 inet или man 4 unix.
Структура sockaddr_un глядит так:
struct sockaddr_un {
u_char sun_len;
u_char sun_family;
char sun_path[104];
};
sun_len - длина структуры, sun_family, sun_path. Bind создает объект спец типа с именем, указанным в sun_path. Если объект уже существует, bind() вернет ошибку. Обычно sun_path - системный вызов bind создает специальный файловый объект типа сокет с именем, указанным в sun_path. Если такой уже существует - bind вернет ошибку. Перед вызовом bind лучше удалить объект с таким именем (в случае уверенности в своих действиях).
Обычно здесь указывают полное имя файлового объекта (начиная со /). Если указывать относительное - чтобы клиент мог найти сервер, и клиент, и сервер должны запускаться из одной и той же директории.
Путь, указанный в sun_path должен обязательно оканчиваться нулевым символом.
Третий параметр bind - длина области данных,в которой записан адрес сокета.
Очередь запросов создают с помощью вызова listen().
listen(< номер сокета, для которого создается очередь запросов >, < длина этой очереди >);
Мы тем самым сообщаем ОС, что программа является сервером, а не клиентом. У вызова два параметра: номер сокета, для которого создается очередь, и длина этой очереди. Большинство ОС не использует число запросов напрямую, а использует его как приближение. В частности, указав число больше 5, очередь будет практически бесконечной.
Дальше мы должны запросы вынимать с помощью системного вызова accept().
accept(< номер сокета >, < адрес буфера >, < входной/выходной параметр, на входе - длина буфера, на выходе - сколько байтов было реально записано >);
Он ждет, пока в очереди появится запрос, и как только он появляется, он возвращает управление серверу. У вызова три параметра: номер сокета, адрес буфера, в который запишется адрес сокета клиента, входной/выходной: длина буфера/сколько реально байт было записано. Третьим параметром передается не число,а указатель на это число. Обычно accept выполняется в цикле. Он возвращает присоединенный сокет. Это такой сокет, который связан непосредственно с тем клиентом, запрос от которого мы только что вынули, то есть он предназначается для общения между собой клиента и сервера.
(Это такой сокет, который связан непосредственно с тем клиентом, чей запрос мы только что вынули. Используется для индивидуального общения с клиентом).
Чтобы передать данные, используется вызов read()
read (<номер присоединенного сокета>);
в котором параметр - номер присоединенного сокета. Мы с его помощью можем прочитать данные с клиента.
После всего этого мы можем послать результаты обработки с помощью write().
write (< номер присоединенного сокета >);
Для разрыва соединения надо использовать вызов close().
close (< номер присоединенного сокета>);
Дата добавления: 2014-12-19; просмотров: 35 | Поможем написать вашу работу | Нарушение авторских прав |