Сервер сокета в C++
Серверный сокет создают через socket,
привязывают к порту и переводят в режим прослушивания.
Вызов accept блокирует поток, пока клиент
не подключится; он возвращает отдельный дескриптор
для обмена с этим клиентом. Входящие байты читают
recv в буфер фиксированного размера; ответ
отправляют send. Оба дескриптора закрывают
перед выходом из программы.
Примем одного клиента на 127.0.0.1 и порту
18080, прочитаем строку и отправим ответ с
префиксом echo: :
#include <arpa/inet.h>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
int main() {
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) {
return 1;
}
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(18080);
if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
close(listen_fd);
return 1;
}
if (bind(listen_fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
close(listen_fd);
return 1;
}
if (listen(listen_fd, 1) == -1) {
close(listen_fd);
return 1;
}
int peer_fd = accept(listen_fd, nullptr, nullptr);
if (peer_fd == -1) {
close(listen_fd);
return 1;
}
char buf[128];
ssize_t got = recv(peer_fd, buf, sizeof(buf) - 1, 0);
if (got == -1) {
close(peer_fd);
close(listen_fd);
return 1;
}
buf[got] = '\0';
std::string reply = std::string("echo: ") + buf;
if (send(peer_fd, reply.c_str(), reply.size(), 0) == -1) {
close(peer_fd);
close(listen_fd);
return 1;
}
close(peer_fd);
close(listen_fd);
return 0;
}
Схема та же: один accept, одно чтение и один
ответ. Во втором примере добавим вывод ответа на
стороне клиента - для этого клиент запускают отдельно
после старта сервера. Сервер вернет строку с префиксом
ok: :
#include <arpa/inet.h>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <string>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
int main() {
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) {
return 1;
}
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(18080);
if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
close(listen_fd);
return 1;
}
if (bind(listen_fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
close(listen_fd);
return 1;
}
if (listen(listen_fd, 1) == -1) {
close(listen_fd);
return 1;
}
int peer_fd = accept(listen_fd, nullptr, nullptr);
if (peer_fd == -1) {
close(listen_fd);
return 1;
}
char buf[128];
ssize_t got = recv(peer_fd, buf, sizeof(buf) - 1, 0);
if (got == -1) {
close(peer_fd);
close(listen_fd);
return 1;
}
buf[got] = '\0';
std::string reply = std::string("ok: ") + buf;
if (send(peer_fd, reply.c_str(), reply.size(), 0) == -1) {
close(peer_fd);
close(listen_fd);
return 1;
}
close(peer_fd);
close(listen_fd);
return 0;
}
После строки "ask\n" от клиента сервер
отвечает "answer: ask"; клиент выводит
эту строку в консоль.
Сервер возвращает клиенту текст "pong",
если получил "ping"; в консоли клиента
должно быть "pong".