Я делаю простой чат, который должен отправить текстовое сообщение, сделанное одним участником всем остальным участникам. Формат сообщения, которое должен получить каждый, - «[IP]: привет!». Также сервер должен уведомлять всех, когда кто-то подключается или отключается: «[IP] подключился» и «[IP] отключен» соответственно.
Вот фрагмент кода, который реализует эту функцию сервера. Вы можете начать поиск, так как строка, содержащая комментарий «ПРОБЛЕМА ЗДЕСЬ»:
while (true)
{
// select() for reading
static constexpr int bufferSize = 1024;
static char buffer[bufferSize];
// this is for getting IP-address of sender
static sockaddr_in sockAddr;
static socklen_t sockAddrSize;
if (FD_ISSET(masterSocket, &set)) // masterSocket is a socket that establishes connections
{
sockAddrSize = sizeof(sockAddr);
int slaveSocket = accept(masketSocket, &sockAddr, &sockAddrSize); // slaveSocket is a client socket
// setting a slaveSocket non-blocking
sprintf(buffer, "[%d.%d.%d.%d] has connected\n",
(sockAddr.sin_addr.s_addr & 0x000000FF),
(sockAddr.sin_addr.s_addr & 0x0000FF00) >> 8,
(sockAddr.sin_addr.s_addr & 0x00FF0000) >> 16,
(sockAddr.sin_addr.s_addr & 0xFF000000) >> 24);
for (const auto &socket : slaveSockets)
send(socket, buffer, strlen(buffer), MSG_NOSIGNAL);
slaveSockets.insert(slaveSocket);
}
for (const auto &socket : slaveSockets)
{
if (FD_ISSET(socket, &set))
continue;
static int recvSize = recv(socket, buffer, bufferSize, MSG_NOSIGNAL);
if (recvSize == 0 && errno != EAGAIN)
{
sockAddrSize = sizeof(sockAddr);
getsockname(socket, (sockaddr *) &sockAddr, &sockAddrSize);
sprintf(buffer, "[%d.%d.%d.%d] has disconnected\n",
(sockAddr.sin_addr.s_addr & 0x000000FF),
(sockAddr.sin_addr.s_addr & 0x0000FF00) >> 8,
(sockAddr.sin_addr.s_addr & 0x00FF0000) >> 16,
(sockAddr.sin_addr.s_addr & 0xFF000000) >> 24);
shutdown(socket, SHUT_RDWR);
close(socket);
slaveSockets.erase(socket);
for (const auto &socket : slaveSockets)
send(socket, buffer, strlen(buffer), MSG_NOSIGNAL);
}
else if (recvSize > 0) // THE PROBLEM IS HERE
{
static char reply[bufferSize];
sockAddrSize = sizeof(&sockAddr);
getsocklen(socket, (sockaddr *) &sockAddr, &sockAddrSize);
sprintf(reply, "[%d.%d.%d.%d]: %s\n",
(sockAddr.sin_addr.s_addr & 0x000000FF),
(sockAddr.sin_addr.s_addr & 0x0000FF00) >> 8,
(sockAddr.sin_addr.s_addr & 0x00FF0000) >> 16,
(sockAddr.sin_addr.s_addr & 0xFF000000) >> 24,
buffer);
int senderSocket = socket;
for (const auto &socket : slaveSockets)
{
if (socket == senderSocket)
continue;
send(socket, reply, strlen(reply), MSG_NOSIGNAL); // even tried the "strlen(reply) + 1"
}
}
}
}
Проблема заключается в том, что получатели неправильно выводят каждое сообщение: оно полностью выводится, но также имеет конец старых значений:буфер в конце. Например:
Клиент A подключился.
Клиент B подключился. Клиент A получил «[127.0.0.1] подключился».
Клиент A отправил «привет». Клиент B получил "[127.0.0.1]: привет \ n0.1] подключился \ n".
Клиент B отправил "что случилось?". Клиент A получил «[127.0.0.1]: что случилось? \ Nподключен \ n».
Клиент A отключен. Клиент B получил «[127.0.0.1] отключен».
Как вы можете видеть, информация о подключении / отключении всегда выводится правильно, но чат работает неправильно: в его конце содержатся части информации о подключении / отключении.
Я искренне верю, что правильно использую буферы и не могу понять, что я делаю неправильно.