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 подобных систем с использованием стандартных библиотек.
Подробнее о работе с сокетами в других системах можно посмотреть по ссылкам (указаны в разделе «Полезные ссылки»)
