См.также
Сокеты
(англ. socket — разъём) — название программного интерфейса для
обеспечения обмена данными между процессами. Процессы при таком обмене
могут исполняться как на одной ЭВМ, так и на различных ЭВМ, связанных
между собой сетью. Сокет — абстрактный объект, представляющий конечную
точку соединения.
Каждый процесс может создать слушающий сокет (серверный сокет) и привязать его к какому-нибудь порту операционной системы (в UNIX непривилегированные процессы не могут использовать порты меньше 1024). Слушающий процесс обычно находится в цикле ожидания, то есть просыпается при появлении нового соединения. При этом сохраняется возможность проверить наличие соединений на данный момент, установить тайм-аут для операции и т.д.
Каждый сокет имеет свой адрес. ОС семейства UNIX могут поддерживать много типов адресов, но обязательными являются INET-адрес и UNIX-адрес. Если привязать сокет к UNIX-адресу, то будет создан специальный файл (файл сокета) по заданному пути, через который смогут сообщаться любые локальные процессы путём чтения/записи из него (см. Доменный сокет Unix). Сокеты типа INET доступны из сети и требуют выделения номера порта.
Обычно клиент явно подсоединяется к слушателю, после чего любое чтение или запись через его файловый дескриптор будут передавать данные между ним и сервером.
Общие | |
Socket | Создать новый сокет и вернуть файловый дескриптор |
Send | Отправить данные по сети |
Receive | Получить данные из сети |
Close | Закрыть соединение |
Серверные | |
Bind | Связать сокет с IP-адресом и портом |
Listen | Объявить о желании принимать соединения. Слушает порт и ждет когда будет установлено соединение |
Accept | Принять запрос на установку соединения |
Клиентские | |
Connect | Установить соединение |
См.также
Создаёт конечную точку соединения и возвращает файловый дескриптор. Принимает три аргумента:
domain указывающий семейство протоколов создаваемого сокета
type
protocol
Протоколы обозначаются символьными константами с префиксом IPPROTO_* (например, IPPROTO_TCP или IPPROTO_UDP). Допускается значение protocol=0 (протокол не указан), в этом случае используется значение по умолчанию для данного вида соединений.
Примечание
Функция возвращает −1 в случае ошибки. Иначе, она возвращает целое число, представляющее присвоенный дескриптор.
Пример на Си
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
// Задаем номер порта
portno = atoi(argv[2]);
// Создаем сокет
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
// Конвертирует имя хоста в IP адрес
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
// Указываем тип сокета Интернет
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
// Указаваем адрес IP сокета
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
// Указываем порт сокета
serv_addr.sin_port = htons(portno);
// Устанавливаем соединение
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
// Вводим сообщение из консоли
printf("Please enter the message: ");
bzero(buffer, 256);
fgets(buffer, 255, stdin);
// Отправляем данные
n = write(sockfd, buffer, strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
// Сбрасываем буфер
bzero(buffer, 256);
// Читаем ответ
n = read(sockfd, buffer, 255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n", buffer);
close(sockfd);
return 0;
}
Пример на Python
import socket
# Создание объекта сокета.
sock_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
# AF_INET, SOCK_STREAM и 0 используются по умолчанию при создании сокета.
# Поэтому можно просто писать:
sock_obj = socket.socket()
См.также
Связывает сокет с конкретным адресом. Когда сокет создается при помощи socket(), он ассоциируется с некоторым семейством адресов, но не с конкретным адресом. До того как сокет сможет принять входящие соединения, он должен быть связан с адресом. bind() принимает три аргумента:
Примечание
Возвращает 0 при успехе и −1 при возникновении ошибки.
Пример на Си
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
Пример на Python
server_address = ('localhost', 8080)
sock_obj.bind(server_address) # Привязка адреса и порта к сокету.
Автоматическое получение имени хоста.
host = socket.gethostname() # Получить имя локальной машины.
server_address = (host, 8080)
sock_obj.bind(server_address) # Привязка адреса и порта к сокету.
См.также
Подготавливает привязываемый сокет к принятию входящих соединений. Данная функция применима только к типам сокетов SOCK_STREAM и SOCK_SEQPACKET. Принимает два аргумента:
Примечание
После принятия соединения оно выводится из очереди. В случае успеха возвращается 0, в случае возникновения ошибки возвращается −1.
Пример на Си
#include <sys/socket.h>
int listen(int sockfd, int backlog);
Пример на Python
sock_obj.listen(5) # Ждем соединение клиента.
См.также
Используется для принятия запроса на установление соединения от удаленного хоста. Принимает следующие аргументы:
Примечание
Функция возвращает дескриптор сокета, связанный с принятым соединением, или −1 в случае возникновения ошибки.
Пример на Си
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
Пример на Python
conn, addr = sock_obj.accept() # Установление соединения с клиентом.
См.также
Устанавливает соединение с сервером.
Некоторые типы сокетов работают без установления соединения, это в основном касается UDP-сокетов. Для них соединение приобретает особое значение: цель по умолчанию для посылки и получения данных присваивается переданному адресу, позволяя использовать такие функции как send() и recv() на сокетах без установления соединения.
Загруженный сервер может отвергнуть попытку соединения, поэтому в некоторых видах программ необходимо предусмотреть повторные попытки соединения.
Примечание
Возвращает целое число, представляющее код ошибки: 0 означает успешное выполнение, а −1 свидетельствует об ошибке.
Пример на Си
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
Пример на Python
server_address = ('192.168.1.100', 8080)
sock_obj.connect(server_address)
Для передачи данных можно пользоваться стандартными функциями чтения/записи файлов read и write, но есть специальные функции для передачи данных через сокеты:
Нужно обратить внимание, что при использовании протокола TCP (сокеты типа SOCK_STREAM) есть вероятность получить меньше данных, чем было передано, так как ещё не все данные были переданы, поэтому нужно либо дождаться, когда функция recv возвратит 0 байт, либо выставить флаг MSG_WAITALL для функции recv, что заставит её дождаться окончания передачи. Для остальных типов сокетов флаг MSG_WAITALL ничего не меняет (например, в UDP весь пакет = целое сообщение).
См.также
send, sendto - отправка данных.
Пример на Си
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int s, const void *buf, size_t len, int flags);
ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
Пример на Python
IP = '192.168.1.100'
PORT = 8080
sock_obj.send('Hello World!')
sock_obj.sendto('Hello World!', (IP, PORT))
См.также
recv, recvfrom - чтение данных из сокета.
Пример на Си
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int s, void *buf, size_t len, int flags);
ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
Пример на Python
BUFFER_SIZE = 1024
data = conn.recv(BUFFER_SIZE)
data, sender_addr = conn.recvfrom(BUFFER_SIZE)
Потоковый (SOCK_STREAM) | Дейтаграммный (SOCK_DGRAM) |
---|---|
Устанавливает соединение | Нет |
Гарантирует доставку данных | Нет в случае UDP |
Гарантирует порядок доставки пакетов | Нет в случае UDP |
Гарантирует целостность пакетов | Тоже |
Разбивает сообщение на пакеты | Нет |
Контролирует поток данных | Нет |
TCP гарантирует доставку пакетов, их очередность, автоматически разбивает данные на пакеты и контролирует их передачу, в отличии от UDP. Но при этом TCP работает медленнее за счет повторной передачи потерянных пакетов и большему количеству выполняемых операций над пакетами. Поэтому там где требуется гарантированная доставка (Веб-браузер, telnet, почтовый клиент) используется TCP, если же требуется передавать данные в реальном времени (многопользовательские игры, видео, звук) используют UDP.