有一个程序
#include <Winsock2.h>
#include <stdint.h>
#include <thread>
const uint16_t ANY_VALID_PORT = 12345;
SOCKET sock = INVALID_SOCKET;
void listenPort()
{
sockaddr_in addr {};
int addrSize = sizeof(addr);
accept(sock, (SOCKADDR*)&addr, &addrSize);
}
// #define CORRECT_SEQUENCE
int main()
{
WSADATA wsaData = { 0 };
WSAStartup(MAKEWORD(2, 2), &wsaData);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in clientService {};
clientService.sin_family = AF_INET;
clientService.sin_port = htons(ANY_VALID_PORT);
clientService.sin_addr.s_addr = INADDR_ANY;
bind(sock, (SOCKADDR*)&clientService, sizeof(clientService));
listen(sock, 2);
#ifdef CORRECT_SEQUENCE
system("start cmd");
std::thread listening { listenPort };
#else
std::thread listening { listenPort };
system("start cmd"); //could be virtually any program
#endif
closesocket(sock);
listening.join();
WSACleanup();
}
预期行为:程序结束,而CMD继续在单独的窗口中运行。真实的行为:直到关闭新的cmd程序才结束。当CORRECT_SEQUENCE被定义时,它工作得很好。但是没有它,accept()即使sock关闭也不会返回。调试器告诉我们,我们在join()上遇到了困难。
这种依赖的原因是什么?cmd(甚至是空程序,只有while(1);总的来说,我和我们的港口没有什么关系。
1条答案
按热度按时间n1bvdmb61#
A socket handle created by the WSASocket or the socket function is inheritable by default.
system
启动与CreateProcessA
和bInheritHandles = TRUE
的进程。结果,sock
被复制到子进程。accept
返回控制,当sock
的最后一个句柄关闭,但system("start cmd");
之后cmd
中存在另一个sock
句柄。只有在你关闭cmd - accept返回错误(可能是WSAEINTR
)之后你的代码的两个变体都是错误的。两者都不起作用。您也可以在调用
accept
之前调用closesocket(sock);
。所以一切都是错的system("start cmd");
在外部也不是有效的。此调用CreateProcessA
为 cmd.exe 使用命令行 /c启动cmd -所以第一个cmd运行第二个cmd并退出..WSASocketW
与WSA_FLAG_NO_HANDLE_INHERIT
一起使用,但不能使用socket
1.永远不要使用
system
。使用CreateProcessW
。1.不调用
cmd /c start cmd
。如果您需要cmd -只需execcmd
1.不将句柄(
sock
)传递给另一个线程并并行关闭它