Michael J. Donahoo "TCP/IP Sockets in C, 2nd Edition" / Michael J. Donahoo "Программирование TCP/IP сокетов в Си, 2-ое издание": 2.1 IPv4 TCP клиент
| Английский оригинал | Перевод на русский | |
|---|---|---|
Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
2.1 IPv4 TCP клиент prefer211 16.05.12 в 17:14 |
|
|
Между клиентом и сервером существует важное отличие - на определенных этапах процесса передачи информации они по-разному используют интерфейс сокетов. Сначала мы рассмотрим клиент. Ostrolist 22.05.12 в 17:27 |
||
|
Его работа состоит в том, чтобы установить соединение с пассивно ожидающим контакта сервером. Ostrolist 22.05.12 в 17:30 |
||
|
Связь типичного TCP клиента, включает в себя четыре основных этапа: IamSadist 16.05.12 в 18:29 |
||
|
1. Создание сокета TCP, используя socket(). prefer211 17.05.12 в 07:26 |
||
|
2. Установление соединения с сервером, используя connect(). prefer211 17.05.12 в 07:27 |
||
|
3. Прием и передача, используя send и recv(). prefer211 17.05.12 в 07:28 |
||
|
4. Закрытие соединения с помощью close(). prefer211 17.05.12 в 07:28 |
||
|
TCPEchoClient4.c является реализацией TCP эхо клиента для IPv4. victor8632 31.05.12 в 08:53 |
||
|
TCPEchoClient4.c prefer211 16.05.12 в 17:14 |
||
|
TCPEchoClient4.c делает следующее: prefer211 16.05.12 в 17:14 |
||
|
1. Настройка приложения и разбор параметров: строки 1-21 Ostrolist 22.05.12 в 17:33 |
||
|
· Включение файлов: строки 1-9 Ostrolist 22.05.12 в 17:36 |
||
|
Данные заголовочные файлы содержат объявления стандартных функций и констант API. Обратитесь к документации (например, с помощью команды man) для определения соответствующих вашей системе включаемых файлов с функциями сокетов и структурами данных. Ostrolist 22.05.12 в 17:43 |
||
|
Мы используем наш собственный заголовочный файл Practical.h с прототипами созданных нами функций, которые мы опишем ниже. Ostrolist 22.05.12 в 17:45 |
||
|
· Разбор символьных параметров и проверка на здравый смысл: строки 13-21 Ostrolist 22.05.12 в 17:49 |
||
|
IPv4 адрес и текстовая строка для отправки эхо-сервису передаются в качестве первых двух параметров. Ostrolist 22.05.12 в 17:51 |
||
|
Третьим параметром клиенту можно сообщить порт сервера, но это необязательно. Ostrolist 22.05.12 в 17:52 |
||
|
Если порт не указывается, клиент использует общепринятый номер порта для эхо-сервиса - 7. Ostrolist 22.05.12 в 17:57 |
||
|
2. Создание TCP сокета: строки 23-26 Ostrolist 23.05.12 в 02:09 |
||
|
Мы создаем сокет с помощью функции socket(). Ostrolist 23.05.12 в 02:10 |
||
|
В качестве параметров при создании мы указываем, что создаем сокет для IPv4 (AF_INET), использующий потоковый протокол (SOCK_STREAM), называемый TCP (IPPROTO_TCP). В случае успешного выполнения функция socket() возвращает целочисленный дескриптор или "хэндл" для созданного сокета. Ostrolist 23.05.12 в 02:59 |
||
|
В случае неудачи socket() возвращает -1 и мы вызываем нашу функцию для обработки ошибок - DieWithSystemMessage(), описываемую ниже - чтобы вывести информативную подсказку и завершить работу программы. Ostrolist 23.05.12 в 03:02 |
||
|
3. Подготовка адреса и установка соединения: строки 28-42 victor8632 31.05.12 в 07:48 |
||
|
Подготовка структуры sockaddr_in для сохранения адреса сервера: строки 29-30 victor8632 31.05.12 в 07:50 |
||
|
Для подключения к сокету, мы должны определить адрес и порт, к которому хотим подключиться. victor8632 31.05.12 в 07:51 |
||
|
Определенная нами структура sockaddr_in будет "контейнером" для этой информации. victor8632 31.05.12 в 07:53 |
||
|
Вызов функции memset() гарантирует, что ни в одной части структуры мы явно не установили нулевое значение. victor8632 31.05.12 в 08:29 Вызов функции memset() гарантирует, что любая составляющая структуры, значение которой мы не присвоили явно, содержит ноль. Ostrolist 01.06.12 в 07:27 |
||
|
Заполнение структуры sockaddr_in: строки 31-38 victor8632 31.05.12 в 08:29 |
||
|
Мы должны установить адрес сети (AF_INET), интернет адрес, и номер порта. victor8632 31.05.12 в 08:31 |
||
|
Функция inet_pton() преобразует строковое представление интернет адреса сервера (передается как аргумент командной строки в формате четырехкомпонентной системы записи) в 32-битное бинарное представление. victor8632 31.05.12 в 08:35 |
||
|
Номер порта сервера был конвертирован из командной строки в бинарное представление ранее; вызов функции htons() (“host to network short”) гарантирует, что двоичное представление будет отформатировано в соответствии с требованиями API. (Необходимость этого описана в Главе 5.) victor8632 31.05.12 в 08:41 |
||
|
Подключение: строки 40-42 victor8632 31.05.12 в 08:36 |
||
|
Функция connect() устанавливает соединение между нашим сокетом и сокетом, определённым с помощью адреса и порта внутри структуры sockaddr_in. Ostrolist 01.06.12 в 07:31 |
||
|
Поскольку Sockets API является общим, указатель на структуру адреса sockaddr_in (которая является специфичной для IPv4) должен быть преобразован к общему типу (sockaddr *). Кроме того, функции должен быть предоставлен фактический размер структуры с данными адреса. Ostrolist 01.06.12 в 07:41 |
||
|
4. Посылаем эхо строку на сервер: строки 44-51 victor8632 31.05.12 в 10:35 |
||
|
Определяем длину посылаемой строки и сохраняем ее для последующего использования. victor8632 31.05.12 в 10:37 |
||
|
Указатель на эхо строку подставляется в вызов функции send(); сама строка была сохранена где-то (как аргумент командной строки) при запуске приложения. victor8632 31.05.12 в 10:49 |
||
|
Нам совершенно все равно, где находится строка, нужен только знать адрес первого байта строки и количество байт, которые нужно отправить. (Нужно отметить, что мы не будем посылать символ окончания строки ('\0'), который стоит в конце строки-аргумента, как и в конце любой другой строки в Си). victor8632 31.05.12 в 10:54 |
||
|
send() возвращает количество переданных байт, если функция отработала успешно, в противном случае будет возвращено -1. victor8632 31.05.12 в 10:56 |
||
|
Если функция send() не выполняется или передает неверное количество байт, мы должны обработать ошибку. victor8632 01.06.12 в 07:23 |
||
|
Обратите внимание, что ситуация с отправкой неверного количества байт здесь не должна возникнуть. victor8632 01.06.12 в 07:25 |
||
|
Тем не менее, это хорошая идея включать в код проверку на ошибки, так как они могут возникнуть в некоторых контекстах. victor8632 01.06.12 в 07:32 |
||
|
5. Получение эхо ответа от сервера: строки 53-70 victor8632 01.06.12 в 07:32 |
||
|
ТСР - это протокол потока байтов. Одним из подразумеваемых положений данного типа протокола является то, что границы функции send() являются размытыми. victor8632 01.06.12 в 07:38 |
||
|
Другими словами: байты посланные через вызов функции send() на одном конце соединения могут быть не все возвращены посредством одного вызова функции recv() на его другом конце. (Мы обсудим этот вопрос более подробно в главе 7.). victor8632 01.06.12 в 07:42 |
||
|
Так что мы должны получать байты в цикле до тех пор, пока не получим столько байт, сколько послали. victor8632 01.06.12 в 07:45 |
||
|
По всей вероятности, этот цикл выполнится всего лишь раз, потому что в действительности данные с сервера будут возвращены все сразу; однако этого может и не случиться, так что мы должны обеспечить возможность множественного чтения, если это потребуется. victor8632 01.06.12 в 07:52 |
||
|
Это базовый принцип написания приложений с использованием сокетов: вы никогда не должны строить предположения о том, что собирается делать сеть или программа на другом конце соединения. victor8632 01.06.12 в 09:00 |
||
|
Получаем блок байт: строки 57-65 victor8632 31.05.12 в 10:44 |
