我正在使用Winsock API编写程序,因为朋友想要一个简单的程序来检查并查看Minecraft服务器是否正在运行。如果它正在运行它可以正常工作,但是如果它没有运行,程序会冻结,直到我假设连接超时。另一个问题是,如果我有这样的东西(伪代码):
void connectButtonClicked()
{
setLabel1Text("Connecting");
attemptConnection();
setLabel1Text("Done Connecting!");
}
似乎跳过了尝试连接()的权利,完全忽略了它上面的内容。我注意到这一点,因为程序将冻结,但它不会将标签更改为“正在连接”。
这是我的实际连接代码:
bool CConnectionManager::ConnectToIp(String^ ipaddr)
{
if(!m_bValid)
return false;
const char* ip = StringToPConstChar(ipaddr);
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(isalpha(ip[0]))
{
ip = getIPFromAddress(ipaddr);
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr(ip);
service.sin_port = htons(MINECRAFT_PORT);
if(m_socket == NULL)
{
return false;
}
if (connect(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
{
closesocket(m_socket);
return false;
}
else
{
closesocket(m_socket);
return true;
}
return true;
}
CConnectionManager的构造函数中还有代码来启动Winsock API等。
那么,如何避免这种冻结,并允许我在连接期间更新类似进度条的内容?我是否必须在单独的线程中建立连接?我只使用Java中的线程,所以我不知道如何做到这一点:/
另外:我正在使用CLR Windows表单应用程序
我使用的是Microsoft Visual C ++ 2008 Express Edition
答案 0 :(得分:4)
您的代码不会跳过标签更新。更新只涉及发出尚未处理的窗口消息,这就是为什么在连接套接字之前看不到新文本的原因。在连接套接字之前,您必须为新消息抽取消息队列。
对于套接字本身,遗憾的是WinSock API中没有连接超时。您有两种选择来实现手动超时:
1)假设您正在使用阻塞套接字(默认情况下套接字是阻塞的),请在单独的工作线程中执行连接。
2)如果您不想使用线程,请将套接字切换到非阻塞模式。连接套接字将始终立即退出,因此您的主代码不会被阻止,如果连接成功,您将在稍后收到通知。有几种方法可以检测到这种情况,具体取决于您使用的API - WSAAsyncSelect(),WSAAsyncEvent()或select()。
无论哪种方式,当连接正在进行时,在主线程中运行一个计时器。如果连接成功,请停止计时器。如果计时器过去,请断开插座,这将导致连接中止并出现错误。
答案 1 :(得分:1)
也许你想在这里阅读:
为了确保所有数据在关闭之前在连接的套接字上发送和接收,应用程序应该在调用closesocket之前使用shutdown来关闭连接。 http://msdn.microsoft.com/en-us/library/ms740481%28v=VS.85%29.aspx
由于您处于阻止模式,因此仍可能存在一些数据......