【问题标题】:Socket recv() made my string into a char "C:\User" 'C'Socket recv() 将我的字符串变成了一个字符 "C:\User" 'C'
【发布时间】:2022-01-05 13:22:55
【问题描述】:

为什么字符串 a 返回 'C' 而不是 "C:\Users\Desktop\Project phoneedge\ForMark\Top"?

当我在一个空的 c++ 项目中对其进行测试时,在我将一些代码从 ThreadFunction 移动到 StartButton 之前它可以工作(UI 应该不断更新,但套接字 recv() 会阻塞它,导致它只更新一次所以我将 UI 代码移到了开始按钮)

这是服务器代码,按下开始按钮后,启动套接字并创建一个线程来运行listen()accept()和recv()。关闭按钮关闭套接字和线程。

服务器代码(MFC 项目)

void CUIServerDlg::StartButton()
{
    WSADATA Winsockdata;
    int iTCPClientAdd = sizeof(TCPClientAdd);
    WSAStartup(MAKEWORD(2, 2), &Winsockdata);

    TCPServerAdd.sin_family = AF_INET;
    TCPServerAdd.sin_addr.s_addr = inet_addr("127.0.0.1");
    TCPServerAdd.sin_port = htons(8000);

    TCPServersocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    bind(TCPServersocket, (SOCKADDR*)&TCPServerAdd, sizeof(TCPServerAdd));

    bRunning = true;
    hthread = CreateThread(NULL, 0, ThreadFunction, this, 0, &ThreadID);
    WaitForSingleObject(hthread, INFINITE);

    funRunning = true;
    while (funRunning == true) {
        vector<string> caseOne;
    

        /*string a;
        char RecvBuffer[512];//this is the declaration in member class
        int iRecvBuffer = strlen(RecvBuffer) + 1;*/

        **a = RecvBuffer;**//a is a String, RecvBuffer is a path name like c:\user..
        //Find files,This part of code is left out because it should not effect the question
        //put the files found in a vector, then display it on a listbox
        for (string fileVec : caseOne) {

            CString fileunderPath;
            string filevector1 = fileVec;
            fileunderPath = filevector1.c_str();//conversion for AddString
            list1.AddString(fileunderPath);
        }
        
        Sleep(1000);//The code updates every 1 second , when file names are modified is displays immediately.
    }    
}

我想将 Sleep(1000) 更改为 WaitForSingleObject() 以替换 WM_Timer 进行分配,但我不知道既然你需要一个句柄,我要创建另一个线程吗? p>

void CUIServerDlg::CloseButton()
{
    bRunning = false;
    funRunning = false;

    WaitForSingleObject(hthread, INFINITE);
    CloseHandle(hthread);
    closesocket(TCPServersocket);
}

所以在这个项目之前我从来没有学过任何关于套接字和线程的东西,下面的代码的想法是使用一个线程运行一个while循环来不断检查新的cilents来发送东西,一定要纠正如果思维过程有误,我。

DWORD WINAPI CUIServerDlg::ThreadFunction(LPVOID lpParam) {

    CUIServerDlg* This = (CUIServerDlg*)lpParam;
    while (This->bRunning == true) {

        int iListen = listen(This->TCPServersocket, 10);
        if (iListen == INVALID_SOCKET)
            OutputDebugString(_T("FAIL LISTEN\n"));

        This->sAccecpSocket = accept(This->TCPServersocket, (SOCKADDR*)&This->iTCPClientAdd, &This->iTCPClientAdd);
        recv(This->sAccecpSocket, This->RecvBuffer, This->iRecvBuffer, 0);
    }

    return 0;
}

客户端代码(空 c++ 项目)

int main(){
    string a = "C:\\Users\\Desktop\\Project phoneedge\\ForMark\\Top";
    const char* SenderBuffer = a.c_str();
    int iSenderBuffer = strlen(SenderBuffer) + 1;

    WSAStartup(MAKEWORD(2, 2), &WinSockData);
    TCPClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    TCPServerAdd.sin_family = AF_INET;
    TCPServerAdd.sin_addr.s_addr = inet_addr("127.0.0.1");
    TCPServerAdd.sin_port = htons(8000);

    connect(TCPClientSocket,(SOCKADDR*)&TCPServerAdd,sizeof(TCPServerAdd));

    send(TCPClientSocket, SenderBuffer, iSenderBuffer, 0);
    closesocket(TCPClientSocket);

    WSACleanup();
    system("PAUSE");
    return 0;
}

【问题讨论】:

  • recv(This-&gt;sAccecpSocket, This-&gt;RecvBuffer, This-&gt;iRecvBuffer, 0); -- 在通过套接字接收数据时,您的代码根本上是错误的。您应该使用recv 的返回值来了解接收了多少字节,然后使用该返回值来确定如何形成字符串。 不要使用strlenstrcpy之类的函数,或您正在使用的CString的构造函数,因为它们在第一个空字节处停止。
  • 如果您要检查recv 的返回值,我敢打赌它不是1,而是更大的值。如果是这样,那正是问题所在,以及我上面的评论与哪里相关——从recv 返回的数据有一个嵌入的空值,并且您没有正确存储返回给您的所有数据。另外,你要一直循环调用recv,直到收到所有数据或发生错误。
  • 这段代码是逐字逐句的,还是只是一个例子? char RecvBuffer[512]; int iRecvBuffer = strlen(RecvBuffer) + 1; - 如果是这样,你想在这里做什么,获取缓冲区的大小?
  • 代码太多,我不想测试它。但是在 Windows 上只找到一个字符可能暗示一个宽字符串在某处被处理,就好像它是一个窄字符一样。在 UTF16 中,所有 ascii 字符都将它们的值保留在第一个字节中……后面跟着一个 0 字节!只是一个疯狂的猜测,但我不会对此感到惊讶......
  • 附带说明:hthread = CreateThread(...); WaitForSingleObject(hthread, INFINITE); 完全浪费了工作线程。你也可以直接调用ThreadFunction(),结果完全一样——调用线程将被阻塞,直到ThreadFunction()退出。

标签: c++ multithreading sockets mfc


【解决方案1】:

TCP 协议按字节流传递数据。

这意味着客户端逐字节传递数据,而不是一次传递所有数据。

当您收到来自客户端的数据时。通过程序可能没有完成。

所以你需要通过一次recv调用接收到一些数据后检查数据是否传完,然后保存子数据直到接收到所有数据。

【讨论】:

  • 字符串显然已通过,但 strlen 无法正常工作 就像保罗说的,当我执行 iRecvBuffer+1 时,它会传回 C://,所以我使用 sizeof() 修复了它,虽然我仍然不完全确定它是如何工作的。
猜你喜欢
  • 1970-01-01
  • 2012-04-27
  • 2020-08-31
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
  • 2015-06-18
  • 2022-01-13
  • 1970-01-01
相关资源
最近更新 更多