Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Сокеты_методичка.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
104.96 Кб
Скачать

4 Примеры (язык Си)

Программа – сервер

Создание простейшего TCP-сервера состоит из следующих шагов:

  • Создание TCP-сокетов вызовом функции socket().

  • Привязывание сокета к прослушиваемому порту вызовом функции bind(). Перед вызовом bind() программист должен объявить структуру sockaddr_in, очистить ее (при помощи memset()), затем sin_family (PF_INET или PF_INET6) и заполнить поля sin_port (прослушиваемый порт, указать в виде последовательности байтов). Преобразование short int в порядок байтов может быть выполнено при помощи вызова функции htons() (сокращение от «от хоста в сеть»).

  • Подготовка сокета к прослушиванию на предмет соединений (создание прослушиваемого сокета) при помощи вызова listen().

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

  • Соединение с удаленным хостом, которое может быть создано при помощи send() и recv() или write() и read().

  • Итоговое закрытие каждого открытого сокета, который больше не нужен, происходит при помощи close().

Код программы – сервера (Си)

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

int main( void )

{

struct sockaddr_in stSockAddr;

int i32SocketFD = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );

if ( i32SocketFD == -1 )

{

perror( "ошибка при создании сокета" );

exit( EXIT_FAILURE );

}

memset( &stSockAddr, 0, sizeof( stSockAddr ) );

stSockAddr.sin_family = PF_INET;

stSockAddr.sin_port = htons( 1100 );

stSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);

if ( bind(

i32SocketFD,

( const void* )&stSockAddr, /* зачем приведение типа?: нужно, но (const sockaddr* ) а не void */

sizeof( stSockAddr )

) == -1

)

{

perror( "ошибка связывания" );

CloseSocketAndExitWithFailure:

close( i32SocketFD );

exit( EXIT_FAILURE );

}

if ( listen( i32SocketFD, 10 ) == -1 )

{

perror( "ошибка прослушивания" );

goto CloseSocketAndExitWithFailure;

}

for(;;)

{

int i32ConnectFD = accept( i32SocketFD, 0, 0 );

if ( i32ConnectFD < 0 )

{

perror( "ошибка принятия" );

close( i32ConnectFD ); /* нужно ли закрывать сокет после ошибки? */

goto CloseSocketAndExitWithFailure;

}

/* выполнение операций чтения и записи ... */

shutdown( i32ConnectFD, SHUT_RDWR );

close( i32ConnectFD );

}

return 0;

}

Программа – клиент

  • Создание TCP-сокета вызовом socket().

  • Соединение с сервером при помощи connect(), передача структуры sockaddr_in с sin_family с указанными PF_INET или PF_INET6, sin_port для указания порта прослушивания (в байтовом порядке), и sin_addr для указания IPv4 или IPv6 адреса прослушиваемого сервера (также в байтовом порядке).

  • Взаимодействие с сервером при помощи send() и recv() или write() и read().

  • Завершение соединения и сброс информации при вызове close().

Код программы – клиента (Си)

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

int main( void )

{

struct sockaddr_in stSockAddr;

int i32Res;

int i32SocketFD = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );

if ( i32SocketFD == -1 )

{

perror( "Ошибка: невозможно создать сокет" );

exit( EXIT_FAILURE );

}

memset( &stSockAddr, 0, sizeof( stSockAddr ) );

stSockAddr.sin_family = PF_INET;

stSockAddr.sin_port = htons( 1100 );

i32Res = inet_pton( PF_INET, "192.168.1.3", &stSockAddr.sin_addr );

if ( i32Res < 0 )

{

perror( "Ошибка: первый параметр не относится к категории корректных адресов" );

CloseSocketAndExitWithFailure:

close( i32SocketFD );

exit( EXIT_FAILURE );

}

else

if ( !i32Res )

{

perror( "Ошибка: второй параметр не содержит корректного IP-адреса" );

goto CloseSocketAndExitWithFailure;

}

if (

connect(

i32SocketFD,

( const void* )&stSockAddr,

sizeof( stSockAddr )

) == -1

)

{

perror("Ошибка соединения");

goto CloseSocketAndExitWithFailure;

}

/* выполнение операций чтения и записи ... */

shutdown( i32SocketFD, SHUT_RDWR );

close( i32SocketFD );

return 0;

}

(*) Приведены примеры для Unix подобных систем с использованием стандартных библиотек.

Подробнее о работе с сокетами в других системах можно посмотреть по ссылкам (указаны в разделе «Полезные ссылки»)