【发布时间】: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->sAccecpSocket, This->RecvBuffer, This->iRecvBuffer, 0);-- 在通过套接字接收数据时,您的代码根本上是错误的。您应该使用recv的返回值来了解接收了多少字节,然后使用该返回值来确定如何形成字符串。 不要使用strlen或strcpy之类的函数,或您正在使用的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