Несколько сообщений в C++
Одно TCP-соединение может передать несколько
сообщений подряд без нового connect.
Каждую порцию байтов отправляют отдельным
send, ответ читают recv в буфер
известного размера. Нельзя полагаться на перевод
строки от peer, если его не отправляли сами.
На сервере после accept удобно повторить
два цикла чтение-ответ, затем закрыть принятый
дескриптор и прослушивающий сокет:
#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;
}
for (int step = 0; step < 2; ++step) {
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("ack: ") + 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;
}
Клиент выполняет симметричный цикл: два раза отправит строку и прочитает ответ. После второй пары закроет сокет; сервер к этому моменту уже отправил оба ответа:
#include <arpa/inet.h>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
int main() {
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (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(fd);
return 1;
}
if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
close(fd);
return 1;
}
const char* lines[2] = {"part-0\n", "part-1\n"};
for (int step = 0; step < 2; ++step) {
const char* line = lines[step];
if (send(fd, line, std::strlen(line), 0) == -1) {
close(fd);
return 1;
}
char buf[128];
ssize_t got = recv(fd, buf, sizeof(buf) - 1, 0);
if (got == -1) {
close(fd);
return 1;
}
buf[got] = '\0';
std::cout << buf;
}
close(fd);
return 0;
}
Две строки "a\n" и "b\n" уходят с
клиента на 127.0.0.1; сервер печатает
каждую с префиксом "item: ", затем
закрывает соединение.
Клиент после двух строк "n1\n" и
"n2\n" читает ответы "got n1" и
"got n2" и выводит их в консоль.