【问题标题】:C++ Client socket receives only first letter of messageC ++客户端套接字仅接收消息的第一个字母
【发布时间】:2021-04-07 19:29:32
【问题描述】:

过去几天我一直被一个问题困扰。我需要用 C++ 设计一个音乐流媒体应用程序。但是,我发现很难发送从目录中读取文件时获得的文件名。文件名为“sample.wav”和“sample1.wav”,但客户端每次只接收和输出字母 S。虽然如果我从服务器手动发送分配给变量的字符串消息,客户端会收到它只是找到。你能指出我正确的方向吗?

提前致谢。

服务器端

        sockaddr_in hint;
        hint.sin_family = AF_INET;
        hint.sin_port = htons(54000);

        hint.sin_addr.S_un.S_addr = INADDR_ANY;
        // for local ip: inet_pton

        bind(listening, (sockaddr*)&hint, sizeof(hint));

        // max number of open connections (SOMAXCONN)
        listen(listening, SOMAXCONN);

        // waiting for connection
        sockaddr_in client;
        int clientSize = sizeof(client);

        SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);

        SOCKET* client_ptr = &clientSocket;
        char host[NI_MAXHOST];
        // client's remote name

        char service[NI_MAXSERV];
        // the port on which the client connects

        ZeroMemory(host, NI_MAXHOST);
        //ZeroMemory(service, NI_MAXHOST);
        // cleaning memory

        sockList.push_back(&clientSocket);

        if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
        {
            for (int i = 0; i < 2; i++) {
                int postList = send(clientSocket, mainList.GetSongName(i).c_str(), mainList.GetSongName(i).size() + 1,0);
            }
        }
        else {

            inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
            cout << host << " connected on port " << ntohs(client.sin_port) << endl;
        }

        closesocket(listening);
 }

客户端:

string ipAddress = "127.0.0.1";
int port = 54000;

WSAData data;
WORD ver = MAKEWORD(2, 2);

int wsResult = WSAStartup(ver, &data);

if (wsResult != 0) {
    cerr << "Can't start Winsock, Err #:" << wsResult << endl;
    return 0;
}

SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);

if (sock == INVALID_SOCKET) {
    cerr << "Can't create socket. Err #:" << WSAGetLastError << endl;
    return 0;
}

sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);

inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);

//hint.sin_addr.S_un.S_addr = INADDR_ANY;

int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));

bind(sock, (sockaddr*)&hint, sizeof(hint));

if (connResult == SOCKET_ERROR) {
    cerr << "Can't connect to Server, Err #:" << WSAGetLastError() << endl;
    closesocket(sock);
    WSACleanup();
}

char buffer[4096];
string userInput;

ZeroMemory(buffer, 4096);

int msglen;
int numbytes = 0;

int welcomemsg = recv(sock, buffer, sizeof(buffer), 0);

cout << sizeof(buffer) << endl;
cout << "Server >>" << string(buffer, 0, welcomemsg) << endl;

do {
     welcomemsg = recv(sock, buffer, 4096, 0);

    if (welcomemsg > 0) {
        cout << "Server >>" << string(buffer, 0, welcomemsg) << endl;
    }
    else {
        cerr << "Client disconnected" << endl;
    }
} while (welcomemsg > 0);

songList 对象构造函数:

wchar_t* w_Path = (wchar_t*)malloc(strlen(filePath) * sizeof(wchar_t));

mbstowcs(w_Path, filePath, strlen(filePath) + 1);

HANDLE hFind;
WIN32_FIND_DATA data;

LPCWSTR m_Path = w_Path;

memset(&data, 0, sizeof(WIN32_FIND_DATA));

hFind = FindFirstFile(m_Path, &data);

if (hFind != INVALID_HANDLE_VALUE) {
    int i = 0;

    do {
        printf("\n %S", data.cFileName);
        songNames[i] = (char*)data.cFileName;
        i++;
    } while (FindNextFile(hFind, &data));
    FindClose(hFind);
}
else {
    cout << "No songs found in directory" << endl;
}

【问题讨论】:

    标签: c++ file sockets server streaming


    【解决方案1】:

    问题是您在 Unicode 模式下工作,而结构 WIN32_FIND_DATAtypedefd 到 WIN32_FIND_DATAW,因此 songNames[i] = (char*)data.cFileName;wchar_t 字符的字符串重新解释为单字节字符。

    作为多字节,whar_t 字符的字符串看起来像一个以空字符结尾的 1 个字符的字符串。

    作为一个快速而简单的修复,将您的服务器项目模式更改为多字节(注意 - 代码中可能存在更多错误,因此可能需要更多修复才能使其正常工作)。

    但更好的是,继续使用 Unicode 模式并调整代码以使用 wchar_t 字符而不是 char。这意味着将 char buffer[] 更改为 wchar_t buffer[] 并在必要时调整大小值。

    【讨论】:

    • 非常感谢。最后一个问题,recv 函数似乎不适用于 wchar_t 作为缓冲区,有什么解决方法吗?
    • 是的,这是 Winsock API 的一个缺陷(recv 需要 char*,而应该是 void*)。在这里您可以安全地将其转换为(char*):recv(sock, (char*)buffer, sizeof(buffer), 0)
    • 不幸的是,我不得不假设转换提供了相同的结果,因为在转换缓冲区和打印所需的宽版本消息时使用 recv 最终得到相同的结果。 (wcout >"
    • 您也必须在songNames[i] = data.cFileName 修复它。 songNames 应该是 wstring[]
    • 感激不尽!你为我节省了很多小时的搜索时间。
    【解决方案2】:

    你对字符串构造函数的使用不正确

        cout << "Server >>" << string(buffer, 0, welcomemsg) << endl;
    

    应该是

        cout << "Server >>" << string(buffer, welcomemsg) << endl;
    

    【讨论】:

    • 删除 0 刚刚使 cout 输出缓冲区大小,而问题仍然存在。只接收文件的第一个字母。
    猜你喜欢
    • 1970-01-01
    • 2018-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-30
    • 2017-02-13
    • 2018-05-16
    • 1970-01-01
    相关资源
    最近更新 更多