Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11642
Последний выпуск: 19.06.2015

Программирование сокетов

Для обеспечения сетевых коммуникаций используются сокеты. Сокет это конечная точка сетевых коммуникаций. Каждый использующийся сокет имеет тип и ассоциированный с ним процесс. Сокеты существуют внутри коммуникационных доменов. Домены это абстракции, которые подразумевают конкретную структуру адресации и множество протоколов, которое определяет различные типы сокетов внутри домена. Примерами коммуникационных доменов могут быть: UNIX домен, Internet домен, и т.д.

В Internet домене сокет - это комбинация IP адреса и номера порта, которая однозначно определяет отдельный сетевой процесс во всей глобальной сети Internet. Два сокета, один для хоста-получателя, другой для хоста-отправителя, определяют соединение для протоколов, ориентированных на установление связи, таких, как TCP.

  • Создание сокета
  • Привязка к локальным именам
  • Установление связи
  • Передача данных
  • Закрывание сокетов
  • Пример функции, для установления WWW коннекции

Создание сокета

Для создания сокета используется системный вызов socket.

s = socket(domain, type, protocol);

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

  • communication domain - AF_INET (Internet протоколы).
  • type of the socket - SOCK_STREAM; Этот тип обеспечивает последовательный, надежный, ориентированный на установление двусторонней связи поток байтов.

Выше был упомянут сокет с типом stream. Краткое описание других типов сокетов приведено ниже:

  • Datagram socket - поддерживает двусторонний поток данных. Не гарантируется, что этот поток будет последовательным, надежным, и что данные не будут дублироваться. Важной характеристикой данного сокета является то, что границы записи данных предопределены.
  • Raw socket - обеспечивает возможность пользовательского доступа к низлежащим коммуникационным протоколам, поддерживающим сокет-абстракции. Такие сокеты обычно являются датаграм- ориентированными.

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

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

s = socket(AF_INET, SOCK_STREAM, 0);

Привязка к локальным именам

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

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

Для связывания сокета с адресом и номером порта используют системный вызов bind:

bind(s, name, namelen);

Привязываемое имя (name) это строка байт переменной длины, которая интерпретируется поддерживаемым протоколом. Интерпретация может различаться в различных коммуникационных доменах.

Установление связи

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

error = connect(s, serveraddr, serveraddrlen);

которая инициирует установление связи на сокете, используя дескриптор сокета s и информацию из структуры serveraddr, имеющей тип sockaddr_in, которая содержит адрес сервера и номер порта на который надо установить связь. Если сокет не был связан с адресом, connect автоматически вызовет системную функцию bind.

Connect возвращает 0, если вызов прошел успешно. Возвращенная величина -1 указывает на то, что в процессе установления связи произошла некая ошибка. В случае успешного вызова функции процесс может работать с дескриптором сокета, используя функции read и write, и закрывать канал используя функцию close.

Со стороны сервера процесс установления связи сложнее. Когда сервер желает предложить один из своих сервисов, он связывает сокет с общеизвестным адресом, ассоциирующимся с данным сервисом, и пассивно слушает этот сокет. Для этих целей используется системный вызов listen:

error = listen(s, qlength);

где s это дескриптор сокета, а qlength это максимальное количество запросов на установление связи, которые могут стоять в очереди, ожидая обработки сервером; это количество может быть ограничено особенностями системы.

Когда сервер получает запрос от клиента и принимает решение об установлении связи, он создает новый сокет и связывает его с ассоциацией, эквивалентной 'слушающему сокету'. Для Internet домена это означает тот же самый номер порта. Для этой цели используется системный вызов accept:

newsock = accept(s, clientaddr, clientaddrlen);

Сокет, ассоциированный клиентом, и сокет, который был возвращен функцией accept, используются для установления связи между сервером и клиентом.

Передача данных

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

write(s, buf, sizeof(buf)); read(s, buf, sizeof(buf));

Вызовы send и recv практически идентичны read и write, за исключением того, что добавляется аргумент флагов.

send(s, buf, sizeof(buf), flags); recv(s, buf, sizeof(buf), flags);

Могут быть указаны один или более флагов с помощью ненулевых значений, таких, как следующие:

  • MSG_OOB - Посылать/получать данные, характерные для сокетов типа stream.
  • MSG_PEEK - Просматривать данные без чтения. когда указывается в recv, любые присутствующие данные возвращаются пользователю, но сами данные остаются как "непрочитанные". Следующий read или recv вызванный на данном сокете вернет прочитанные в прошлый раз данные.
  • MSG_DONTROUTE - посылать данные без маршрутизации пакетов. (Используется только процессами, управляющими таблицами маршрутизации.)

Закрывание сокетов

Когда взаимодействующие модули решают прекратить передачу данных и закрыть сеанс связи, они обмениваются трехсторонним рукопожатием с сегментами, содержащими установленный бит "От отправителя больше нет данных" (этот бит еще называется FIN бит).

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

close(s);

Если данные были ассоциированы с сокетом, обещающим доставку (сокет типа stream), система будет пытаться осуществить передачу этих данных. Тем не менее, по истечении довольно таки длительного промежутка времени, если данные все еще не доставлены, они будут отброшены. Если пользовательский процесс желает прекратить любую передачу данных, он может сделать это с помощью вызова shutdown на данном сокете для его закрытия. Вызов shutdown вызывает "моментальное" отбрасывание всех стоящих в очереди данных. Формат вызова следующий:

shutdown(s, how);

где how имеет одно из следующих значений:

  • 0 - если пользователь больше не желает читать данные
  • 1 - если данные больше не будут посылаться
  • 2 - если данные не будут ни посылаться ни получаться

Пример функции, для установления WWW коннекции

/*

  MakeConnection

  Function allocates a socket and estabishes a connection
  with remote host. Default port number 80.

  Input : WWW server name (with port number, if it is not 80)
  Output : file descriptor on success
              -1 on error

*/
int MakeConnection(unsigned char* ServerName){
  int s;
  struct sockaddr_in ssin;
  struct hostent* hp;
  int PortNum;
  unsigned char strHlp[STRNGLEN], *pch;

  /* use default port number - 80 or specific number from the
     server name */
  strcpy(strHlp,ServerName);
  pch = strchr(strHlp,':');
  if(pch==NULL){
    PortNum = 80;
  }else{
    pch[0] = '';
    pch++;
    PortNum = atoi(pch);
    if(PortNum==0){
      PortNum = 80;
    }
  }

  /* get host by name - resolve host name into IP address */
  if( (hp=gethostbyname(strHlp)) == NULL  )
  {
     return -1;
  }

  bzero(&ssin, sizeof(ssin));
  bcopy(hp->h_addr, &ssin.sin_addr, hp->h_length);
  ssin.sin_family = hp->h_addrtype;
  ssin.sin_port = htons(PortNum);

  /* allocate a socket */
  if((s=socket(AF_INET, SOCK_STREAM, 0))==-1)
  {
     return -1;
  }

  /* make a connection */
  if(connect(s, &ssin, sizeof(ssin), 0)==-1){

     return -1;
  }

  return s; /* socket descriptor */
}

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
99K
13 сентября
Евгений КУЛИК
0 / / 13.09.2017
Мне нравитсяМне не нравится
13 сентября 2017, 13:41:52
Compile the code below with this line.

g++ -std=c++14 socksender.cpp -o socksender
2.
99K
13 сентября
Евгений КУЛИК
0 / / 13.09.2017
Мне нравитсяМне не нравится
13 сентября 2017, 13:40:50
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>

/*
#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
*/

#define STRNGLEN 4096

int MakeConnection(char* ServerName){
int s;
struct sockaddr_in ssin;
struct hostent* hp;
int PortNum;
char strHlp[STRNGLEN], *pch;

/* use default port number - 80 or specific number from the
server name */
strcpy(strHlp,ServerName);
pch = strchr(strHlp,':');
if(pch==NULL){
PortNum = 9999;
}else{
pch[0] = 0x00;
pch++;
PortNum = atoi(pch);
if(PortNum==0){
PortNum = 9999;
}
}

/* get host by name - resolve host name into IP address */
if( (hp=gethostbyname(strHlp)) == NULL )
{
return -1;
}

bzero(&ssin, sizeof(ssin));
bcopy(hp->h_addr, &ssin.sin_addr, hp->h_length);
ssin.sin_family = hp->h_addrtype;
ssin.sin_port = htons(PortNum);

/* allocate a socket */
if((s=socket(AF_INET, SOCK_STREAM, 0))==-1)
{
return -1;
}

/* make a connection */
if(connect(s,reinterpret_cast<const sockaddr*> ( &ssin ), sizeof(ssin))==-1){

return -1;
}

return s; /* socket descriptor */
}

int main()
{
char localhost[] = "localhost";
auto handle = MakeConnection(localhost);
while (true)
{
auto test = "test/n";
send(handle,test,sizeof(test) - 1,0);
usleep(1);
}
return 0;
}
3.
98K
11 мая
иван
0 / / 11.05.2017
+1 / -1
Мне нравитсяМне не нравится
11 мая 2017, 22:34:13
У кого не получается, у того просто руки не из того места растут. Учитесь читать английские документации, там все намного яснее расписано!
4.
46K
26 декабря 2008 года
MET-MW
0 / / 26.12.2008
+5 / -1
Мне нравитсяМне не нравится
26 декабря 2008, 00:46:42
Чтож такое то... куда ни зайдёшь - везде один и тот же исходник. Ну не помогает он мне нифига! В нём даже нет примера передачи байтов (с которыми кстати и проблема)! Вот например: "send(s, buf, sizeof(buf)". Что подразумевается под "s"??? Это дискриптор сокета отправителя, получателя или вновь созданного для подключения сокета(в случае передачи от сервера к клиенту)????? Аналогичный вопрос с приёмом сообщения. Спасибо огромное, если кто ни будь ответит.
5.
Аноним
+1 / -1
Мне нравитсяМне не нравится
22 апреля 2006, 16:18:49
Статья полная лажа.
Напоминает обыкновенну отписку, как говорится чтобы было на сайте. Рассказ ни туда ни сюда, как и везде блин:
1. как создать сокет как прослушать и как сендить
2. потом идёт банальный исходный код, который кроме как в попу никуда не сунешь.

Ты лучше расскажи как работает та или иная сетевая прога(хотя бы Smash chat), это будеть полезнее.
И не трать время на писанину того чем сеть завалена.

Рассказывай про более серьёзные вещи... а как создать и прослушать сокет это люди и без тебя смогут узнать, а вот дальше это уже проблема(на своём опыте знаю)...

Желаю успехов.
6.
Аноним
Мне нравитсяМне не нравится
2 апреля 2006, 04:20:18
А про асинхронные сокеты кто будет писать. Нужно рассматривать все аспекты. Сначало попроще потом посложнее. Или статью называть "Socket для чайников".
7.
Аноним
+0 / -1
Мне нравитсяМне не нравится
24 января 2006, 20:04:03
Хто знає чи підходить даний код до UDP протоколу?
8.
Аноним
+0 / -1
Мне нравитсяМне не нравится
28 ноября 2005, 16:34:27
)))мерси за хелпу, я рада. мне помогло, ет точняк!!!=)))
9.
Аноним
Мне нравитсяМне не нравится
30 мая 2005, 07:18:14
В случае UDP-соединения на передачу все работает. А на прием-нет. Почему?
10.
Аноним
Мне нравитсяМне не нравится
14 апреля 2005, 12:52:08
маклево!!! мне помогло! Спасибо создателю!!!
11.
Аноним
Мне нравитсяМне не нравится
10 марта 2005, 01:25:09
Желательно расширить пример до классов С++.
12.
Аноним
Мне нравитсяМне не нравится
16 февраля 2005, 12:10:20
Очень хороший пример, но...
не хватает комментариев в исходном тексте программы, например не понятно, что делает: bzero(...), bcopy(...)
12.1.
98K
11 мая
иван
0 / / 11.05.2017
Мне нравитсяМне не нравится
11 мая 2017, 22:36:03
Наберите man 3 bzero и увидите. Линукс используйте как учебник и все получится!
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог