Материалы к лабораторным

advertisement
Мельников В.Ю.
Справочные материалы к лабораторным работам
по курсу «Сети и телекоммуникации»
2010 г.
Коммуникации через COM порт (интерфейс RS232)
Физический уровень
К COM порту компьютера подключается разъем DB9F
Контакт
сигнал
примечание
разъема DB9F
1
in
DCD
Определение несущей
2
in
RD – receives data
прием данных
3
out TD – transmit data
передача данных
4
out DTR - data-terminal-ready Готовность терминала
5
SG – signal ground
Сигнальное заземление
6
in
DSR - data-set-ready
Готовность к работе
7
out RTS - request-to-send
Запрос на передачу (Данные готовы для
передачи)
8
in
CTS - clear-to-send
Готовность к приему
9
in
RI
Индикатор вызова
Жирным шрифтом помечены минимально необходимые сигналы.
Сигналы готовности к приему данных можно заменить передачей байта данных XON(11h) /
XOFF(13h) или просто игнорировать.
Для обмена между двумя компьютерами и некоторыми устройствами с интерфейсом RS232
используется следующий кабель:
2
3
5
4
6
1
7
8
2 -RD
3 - TD
5 - SG
4 - DTR
76 -- RTS
DSR
1 - DCD
8 - CTS
DB9F (компьютер)
5
1
9
6
DB9M
1
5
6
9
Некоторые устройства с интерфейсом RS232 подключаются следующим кабелем
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
Логическая единица соответствует уровню сигнала в диапазоне +3V…+15V (обычно +12V)
Логический нуль соответствует уровню сигнала в диапазоне -3V…-15V (обычно -12V)
Максимальный ток 20mA. Максимальная скорость передачи 115200 бод (11520 байт/с).
Максимальная длина кабеля
Скорость передачи
Экранированный кабель
Неэкранированный кабель
2400
304м
152м
4800
304м
76м
9600
76
76
2
Формат передачи байта данных
stop Start 1
2
P – бит четности
3
4
5
6
7
8
P
stop start
Функции работы с COM портом
1. Открываем COM порт
HANDLE m_hCom=CreateFile(“COM1”,
GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0,NULL);
2. Настраиваем параметры порта
DCB dcb;
GetCommState(m_hCom, &dcb);
dcb.DCBlength=sizeof(DCB);
dcb.fBinary=1;//должен быть 1
dcb.BaudRate=9600;
dcb.ByteSize=8;
dcb.fParity=0;//игнорировать правильность принимаемых данных.
dcb.fOutxCtsFlow=0;//посылать данные, игнорируя сигнал CTS от устройства
dcb.fOutxDsrFlow=0;//посылать данные, игнорируя DSR от устройства
dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.fRtsControl=RTS_CONTROL_ENABLE;
dcb.Parity=NOPARITY;
dcb.StopBits=ONESTOPBIT;
DWORD dwRes=SetCommState(m_hCom, &dcb);
if(dwRes==0)
{
char strErr[1024];
sprintf(strErr,"Ошибка настройки COM порта %d",GetLastError());
::MessageBox(NULL,strErr,"Ошибка",MB_OK|MB_ICONERROR);
CloseHandle(m_hCom);
return(0);
}
3. Настраиваем параметры ожидания (если хотим избежать блокировки программы без
организации параллельных процессов)
COMMTIMEOUTS TO;
GetCommTimeouts(m_hCom,&TO);
TO.ReadIntervalTimeout=100;//max интервал между приемом двух символов (или 0)
TO.ReadTotalTimeoutMultiplier=100;
TO.ReadTotalTimeoutConstant=100;
//max время приема блока данных при вызове ReadFile(N)
//равно ReadTotalTimeoutConstant+ N* ReadTotalTimeoutMultiplier
//0 = время не ограничено
TO.WriteTotalTimeoutConstant=100;
TO.WriteTotalTimeoutMultiplier=100;
//max время передачи блока данных при вызове WriteFile(N)
//равно WriteTotalTimeoutConstant + N* WriteTotalTimeoutMultiplier
//0 = время не ограничено
SetCommTimeouts(m_hCom,&TO);
4. Почистим буфера обмена
PurgeComm(m_hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
3
5. Передаем данные (При использовании параллельных процессов следует избегать
одновременной работы функций WriteFile() и ReadFile() с одним портом)
BYTE abBuf[256];//массив передаваемых данных
DWORD dwRead= 255;//передаем байт
DWORD dwAct = 0;//реально переданных байт
if(WriteFile (m_hCom,abBuf, dwRead, &dwAct,NULL) && dwAct !=0)
{…}
6. Принимаем данные
BYTE abBuf[256];//массив для принятых данных
DWORD dwRead= 255;//ждем байт
DWORD dwAct = 0;//реально принятых байт
if(ReadFile(m_hCom,abBuf, dwRead, &dwAct,NULL) && dwAct !=0)
{…}
7. Освобождаем порт
CloseHandle(m_hCom);
Канальный уровень
Протокол PPP (Point to Point Protocol)
Не требует DTR, RTS и других управляющих сигналов
1 стартовый бит, 8 бит данных, без проверки четности, 1 стоп бит.
Данные
Контрольная Флаг
Флаг Адрес Управляющее Протокол
FFh
поле 03h
сумма
7Eh
7Eh
1 байт 1 байт
1 байт
2 байта
2 байта
1 байт
Байт данных 7Eh заменяется на 2 байта 7D5Eh.
Байт данных 7Dh заменяется на 2 байта 7D5Dh.
Протокол: 0021h=IP, С021h =LCP (протокол установки соединения), С023h=PAP(Password
Authentification Protocol)…
4
Технологии Ethernet
Физический уровень
Тонкий Ethernet 10Base-2 (длина сегмента до 185 метров)
компьютер
компьютер
терминатор
компьютер
терминатор
T-коннекторы
Кабель – коаксиальный, разъем BNC
Витая пара 10Base-T, 100 Base-T, 1000 Base-T (длина кабеля до 100 метров)
компьютер
компьютер
компьютер
компьютер
компьютер
Концентратор (HUB)
или
Коммутатор (Switch)
Кабель – витая пара, разъем RJ45
Компьютер - Компьютер коммутатор компьютер
RJ45 (вилка)
8
7
6
5
4
3
2
1
Коричневый
Бело-коричневый
Зеленый
Бело-синий
Синий
Бело-зеленый
Оранжевый
Бело-оранжевый
8
7
6
5
4
3
2
1
RxRx+
TxTx+
Канальный уровень
Ethernet II
Преамбула
Адрес
Адрес
Протокол
получателя получателя
8 байт
6 байт
6 байт
2 байта
Протоколы: IP=0800h, ARP=0806h, RARP=0835h…
Широковещательный адрес=FFFFFFFFFFFFh
Данные
46-15000 байт
Контрольная
сумма
4 байта
5
Протоколы UDP и TCP/IP
Формат заголовка UDP (User Datagram Protocol)
Версия IP Длина
Тип обслуживания
Общая длина IP-дейтаграммы в байтах
4 бита заголовка
8 бит
16 бит
Идентификация IP- дейтаграммы
Флаги
Смещение фрагмента
16 бит
3 бита
13 бит
TTL
Протокол =17
Контрольная сумма заголовка
8 бит
8 бит
16 бит
IP адрес отправителя
32 бита
IP адрес получателя
32 бита
Порт отправителя
Порт получателя
16 бит
16 бит
Длина UDP (8 байт заголовка + данные)
Контрольная сумма UDP
16 бит
16 бит
Данные
(если есть)
Серым цветом помечены данные IP пакета, в который инкапсулирован пакет UDP
(Версия=4(Ipv4); Длина заголовка в 4 байтовых словах; Флаги – флаги фрагментизации; TTL –
время жизни – максимальное число маршрутизаторов, через которые может пройти дейтаграмма).
Длина заголовка в четырехбайтовых словах.
Длина IP заголовка 20 байт (минимум)
Длина UDP заголовка 8 байт (минимум)
Фрагменты программы для работы с UDP
1. Необходимо подключить
#include <Winsock2.h>//описание функций
#pragma comment(lib, "Ws2_32.lib")//подключаем библиотеку
2. Запускаем WSA
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1, 1);
if(::WSAStartup(wVersionRequested, &wsaData)!=0)
{printf(“Ошибка %X”,WSAGetLastError());return;}
3. Создаем «сокет»
SOCKET S=socket(PF_INET,SOCK_DGRAM,0);
if(S==INVALID_SOCKET)
{printf(“Ошибка %X”,WSAGetLastError());return;}
4. Готовим адрес получателя
u_long IA=inet_addr(strName);//адрес в виде 11.22.33.44
if(IA==INADDR_NONE)
{//возможно задано DNS имя
LPHOSTENT lphost=::gethostbyname(strName);
if (lphost==NULL){printf(“Ошибка %X”,WSAGetLastError());return;}
IA=((in_addr FAR *)lphost->h_addr)->s_addr;
}
sockaddr_in SA;
memset(&SA, 0, sizeof(SA));//заполняем нулями
SA.sin_family = AF_INET;//семейство протокола=IP
SA.sin_addr.S_un.S_addr=IA;
SA.sin_port=::htons(iPort);
5. Отправляем пакет
6
int iSend=::sendto (S,(LPCSTR)m_cstrSend,m_cstrSend.GetLength()+1,0,
(sockaddr *)&SA, sizeof(SA));
if(iSend==SOCKET_ERROR)
{printf(“Ошибка %X”,WSAGetLastError());return;}
6. Принимаем пакет
//определяем допустимый адрес отправителя
sockaddr_in SA;
memset(&SA, 0, sizeof(SA));
SA.sin_family = AF_INET;
SA.sin_addr.S_un.S_addr= ::htonl(INADDR_ANY);//Отправитель любой
SA.sin_port=::htons(iPort);
if (::bind(S, (sockaddr *)&SA, sizeof(SA))!=0)
{printf(“Ошибка %X”,WSAGetLastError());return;}
sockaddr_in SAfrom;//сюда запишется адрес отправителя
int iSzSAfrom=sizeof(SAfrom);
int iRec=::recvfrom(S,strBuf,sizeof(strBuf)-1,0,(sockaddr
*)&SAfrom,&iSzSAfrom);
if(iRec<0){printf(“Ошибка %X”,WSAGetLastError());return;}
7. Освобождаем ресурсы
closesocket(S);
Формат заголовка TCP (Transmission Control Protocol)
Версия IP Длина
Тип обслуживания
Общая длина IP-дейтаграммы в байтах
4 бита заголовка
8 бит
16 бит
Идентификация IP- дейтаграммы
Флаги
Смещение фрагмента
16 бит
3 бита
13 бит
TTL
Протокол = 6
Контрольная сумма заголовка
8 бит
8 бит
16 бит
IP адрес отправителя
32 бита
IP адрес получателя
32 бита
Порт отправителя
Порт получателя
16 бит
16 бит
Порядковый номер первого байта данных в сегменте
32 бита
Номер подтверждения – номер байта, который ожидает приемник
32 бита
Длина
Резерв
Флаги управления
Размер окна в байтах
заголовка
6 бит
6 бит
16 бит
4 бита
Контрольная сумма UDP
Указатель срочности
16 бит
16 бит
Данные
(если есть)
Серым цветом помечены данные IP пакета, в который инкапсулирован пакет UDP
(Версия=4(Ipv4); Длина заголовка в 4 байтовых словах; Флаги – флаги фрагментизации; TTL –
время жизни – максимальное число маршрутизаторов, через которые может пройти дейтаграмма).
Длина заголовка в четырехбайтовых словах.
Флаги управления: URG (вне очереди); ACK (сегмент содержит подтверждение); PSH (получатель
должен пропихнуть данные из приемного буфера в приложение пользователя); RST (оборвать
соединение, очистить буфер); SYN (синхронизация счетчика принимаемых байтов); FIN (передача
данных завершена).
7
Длина IP заголовка 20 байт (минимум)
Длина TCP заголовка 20 байт (минимум)
Состояния сеанса TCP
CLOSED
Начальное состояние узла. Фактически фиктивное
LISTEN
Сервер ожидает запросов установления соединения от клиента
SYN-SENT
Клиент отправил запрос серверу на установление соединения и ожидает
ответа
SYN-RECEIVED Сервер получил запрос на соединение, отправил ответный запрос и ожидает
подтверждения
ESTABLISHED
Соединение установлено, идёт передача данных
FIN-WAIT-1
Одна из сторон (назовём её узел-1) завершает соединение, отправив сегмент с
флагом FIN
CLOSE-WAIT
Другая сторона (узел-2) переходит в это состояние, отправив, в свою очередь
сегмент ACK и продолжает одностороннюю передачу
FIN-WAIT-2
Узел-1 получает ACK, продолжает чтение и ждёт получения сегмента с
флагом FIN
LAST-ACK
Узел-2 заканчивает передачу и отправляет сегмент с флагом FIN
TIME-WAIT
Узел-1 получил сегмент с флагом FIN, отправил сегмент с флагом ACK и
ждёт 2*MSL секунд, перед окончательным разрушением канала
CLOSING
Состояние закрытия соединения (фиктивное?)
Фрагменты программы для работы с TCP
1. Необходимо подключить
#include <Winsock2.h>//описание функций
#pragma comment(lib, "Ws2_32.lib")//подключаем библиотеку
2. Запускаем WSA
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1, 1);
if(::WSAStartup(wVersionRequested, &wsaData)!=0)
{printf(“Ошибка %X”,WSAGetLastError());return;}
3. На стороне сервера создаем принимающий подключения «сокет»
SOCKET Saccept=socket(PF_INET, SOCK_STREAM, 0);
if(Saccept==INVALID_SOCKET)
{printf(“Ошибка %X”,WSAGetLastError());return;}
sockaddr_in SA;
memset(&SA, 0, sizeof(SA));
SA.sin_family = AF_INET;
SA.sin_addr.S_un.S_addr= ::htonl(INADDR_ANY);//Отправитель любой
SA.sin_port=::htons(iPort);
if(::bind(Saccept, (sockaddr *)&SA, sizeof(SA))!=0)
{printf(“Ошибка %X”,WSAGetLastError());return;}
if (::listen(Saccept, 100)!=0)//состояние=ожидание подключений
{printf(“Ошибка %X”,WSAGetLastError());return;}
4. На стороне сервера запускаем процесс приема входящих подключений
DWORD idThread;
HANDLE h=CreateThread(NULL,0,s_LoopAccept, pAccceptData,0,&idThread);
// pAccceptData – адрес объекта с информацией для работы процесса
5. Функция параллельного процесса приема входящих подключений
Struct AccceptData {SOCKET Saccept;/*и прочее*/};
ULONG __stdcall s_LoopAccept(LPVOID pParam)
//выполняется в нити приема входящих подключений
{
AccceptData *pData=(AccceptData *)pParam;
while(TRUE)
{
8
sockaddr_in SAfrom;//сюда запишется адрес отправителя
int iSz=sizeof(SAfrom);
SOCKET S=::accept(pData->Saccept,&SAfrom,&iSz);
//сокет для обмена данными с
if(S==INVALID_SOCKET)
return(0); //какие-то проблемы с сетью или сокет закрыт
//запускаем процесс приема данных
ChannelData *pChannelData=new ChannelData();
pChannelData->S=S;
DWORD idThread;
HANDLE h=CreateThread(NULL,0,s_LoopRead, pChannelData,
0,&idThread);
}
return(0);
}
6. Чтение данных
char bufR[256];
while(TRUE)
{
int iRead=::recv(S, bufR,sizeof(bufR), 0);
if(iRead==0)break;//на другой стороне закрыт сокет
//...
}
::closesocket(S); //закрываем соединение, освобождаем ресурсы
7. Подключение к серверу на стороне клиента
//Готовим адрес получателя
u_long IA=inet_addr(strName);//адрес в виде 11.22.33.44
if(IA==INADDR_NONE)
{//возможно задано DNS имя
LPHOSTENT lphost=::gethostbyname(strName);
if (lphost==NULL){printf(“Ошибка %X”,WSAGetLastError());return;}
IA=((in_addr FAR *)lphost->h_addr)->s_addr;
}
sockaddr_in SA;
memset(&SA, 0, sizeof(SA));//заполняем нулями
SA.sin_family = AF_INET;//семейство протокола=IP
SA.sin_addr.S_un.S_addr=IA;
SA.sin_port=::htons(iPort);
if(::connect(S, (sockaddr *)&SA, sizeof(SA)) < 0)
{printf(“Ошибка %X”,WSAGetLastError());return;}
8. Передача данных
int iSend=::send(S,(char *)pBufW,iSz,0);
8. завершение сеанса
::shutdown(S,SD_SEND);//сообщаем на другой конец о закрытии связи и
прекращаем передавать пакеты
9
Download