我用C++和socket编程写的程序无法在每次消息发送后清除消息

问题描述 投票:0回答:1

程序中的“行”部分需要在每次消息传输后清除,但我一直无法做到这一点。

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdbool.h>
#include <iostream>

const char* ip = "127.0.0.1";
int port = 1752;
#pragma comment (lib, "ws2_32.lib")


int main() {

    WSADATA wsadata;
    if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
        printf("[!] Winsock failed..\n");
        exit(-1);
    }
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        printf("[!] Socket creat was fail..\n");
        WSACleanup();
        exit(-1);
    }
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_port = htons(port);
    inet_pton(AF_INET, ip, &(address.sin_addr));

    if (connect(sock, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR) {

        printf("[!] Connect was fail.. \n");
        closesocket(sock);
        WSACleanup();
        exit(-1);
    }
    char buffer[1024];

    char name[1024];
    printf("Enter the username: \n");
    std::cin.getline(name, sizeof(name));
    size_t nameCount = strlen(name);
    name[strcspn(name, "\n")] = '\0';

    char line[1024];
    printf("Enter the messages: \n");


    while (true) {
        std::cin.getline(line, sizeof(line));
        size_t charCount = strlen(line);
        line[charCount - 1] = '\0';
        line[strcspn(line, "\n")] = '\0';
        sprintf_s(buffer, sizeof(buffer), "%s: %s", name, line);
        if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR) {
            printf("[!] Send failed\n");
            break;
        }
    }
    WSACleanup();
    closesocket(sock);
}

我希望“行”部分在每次消息传输后都被完全清除,并且不会与下一条消息混淆,但它没有被正确清除

c++ sockets char
1个回答
0
投票

您不会在每个

line
之后将
send()
的内容清零。这就是为什么您会看到
line
在下一个
cin.getline()
之后可能仍保留较早的数据。您可以使用
std::memset()
进行归零,例如:

while (std::cin.getline(line, sizeof(line))) {
    ...
    std::memset(line, 0, sizeof(line));
}

另一种选择是注意实际返回给您的字符数

cin.getline()
,并且不要使用比这更多的字符。那么你就不需要浪费时间将
line
归零,或者浪费时间使用
strlen()
来计算输出长度。
cin.gcount()
返回后,输出长度由
cin.getline()
报告。

除此之外,我发现您的代码还存在其他一些问题:

  • 缺乏对

    cin.getline()
    send()
    足够的错误检查。

    • 您不确定

      cin.getline()
      实际上正在向您返回可用数据。

    • send()
      可以(通常确实)返回比请求更少的字节,因此您需要循环调用它,直到所有字节实际上都被接受。

  • 您没有向接收者发送

    buffer
    的长度或任何终止符,因此接收者无法知道每个
    buffer
    消息的实际大小。您需要:

    • 在发送消息本身之前发送消息的长度。然后接收器可以先读取长度,然后读取长度所说的字节/字符。

    • 在消息后发送唯一的终止符,例如

      \n
      \0
      。然后接收器可以读取,直到终结符到达。

  • send()
    循环之后关闭应用程序期间,您在
    WSACleanup()
    之前调用
    closesocket()
    。您需要交换它们。

话虽如此,尝试更像这样的事情:

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>

#pragma comment (lib, "ws2_32.lib")

const char* ip = "127.0.0.1";
int port = 1752;

bool sendRaw(SOCKET sock, const void *buffer, size_t bufsize) {
    const char *pbuf = reinterpret_cast<const char*>(buffer);
    while (buflen > 0) {
        int sent = send(sock, pbuf, static_cast<int>(buflen), 0);
        if (sent == SOCKET_ERROR) {
            std::cerr << "[!] Send failed\n";
            return false;
        }
        pbuf += sent;
        buflen -= sent;
    }
    return true;
}

bool sendStr(SOCKET sock, const std::string& str) {
    return sendRaw(sock, str.c_str(), str.size());
}

int main() {

    WSADATA wsadata;
    if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
        std::cerr << "[!] Winsock startup failed..\n";
        return -1;
    }

    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        std::cerr << "[!] Socket create failed..\n";
        WSACleanup();
        return -1;
    }

    sockaddr_in address = {};
    address.sin_family = AF_INET;
    address.sin_port = htons(port);
    inet_pton(AF_INET, ip, &(address.sin_addr));

    if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == SOCKET_ERROR) {
        std::cerr << "[!] Connect failed.. \n";
        closesocket(sock);
        WSACleanup();
        return -1;
    }

    std::string name;
    std::cout << "Enter the username:\n";

    if (std::getline(std::cin, name) && !name.empty()) {

        std::string line;
        std::cout << "Enter the messages:\n";

        while (std::getline(std::cin, line)) {
            if (!sendStr(sock, name + ": " + line + "\n")) {
                break;
            }
        }
    }

    closesocket(sock);
    WSACleanup();

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.