Winsock“连接”挂起。 Visual Studio报告可能的死锁

时间:2013-07-09 07:42:57

标签: java winapi networking deadlock winsock2

我有这个代码。 (在我的其他旧项目中使用它,工作得非常好)

SOCKET Connect(char * host, int port){
   struct sockaddr_in sin = {0}; 
   struct hostent * entry = 0;

   SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if(s == INVALID_SOCKET){
    return INVALID_SOCKET;
} 

entry = gethostbyname(host);

if(entry == 0){
   closesocket(s);
    return INVALID_SOCKET;
}

sin.sin_addr   = *((LPIN_ADDR)*entry->h_addr_list);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);

// The process becomes dealocked after this line
if( connect(s,(const LPSOCKADDR)&sin,sizeof(SOCKADDR)) == SOCKET_ERROR){
    closesocket(s);
    return INVALID_SOCKET;
}

return s;
}

我今天早上开始使用TTcpClient和Indy的TIdTcpClient包装器处理Delphi项目,我发现该进程没有建立任何连接,而是在调用connect后挂起。然后我切换到C / C ++并尝试使用这个代码执行相同的操作。挂起之后,就没有办法杀死它(除非它正在调试,我必须退出调试器)。 TaskManager,Process Explorer没有做什么。

没有线程或循环或任何可能导致它只挂起此代码的东西以及在连接后写入套接字的另一个函数。

使用Visual Studio进行调试时,有时会显示一条消息(下方)

Visual Studio Error

即使是Wireshark也没有显示任何内容。重新启动我的电脑仍然存在同样的问题。

以前有没有人遇到过这个问题?

二手编译器

  • Visual Studio 2010
  • Pelles-C
  • Delphi 7

操作系统:Windows 7 64位,终极

Winsock版本:2.2

更新

所以我认为我会逃避并转而使用Java只是为了在几次后发现同样的问题。这到底是怎么回事。即使在localhost上,Java也需要大约2分钟才能连接。这个简单的代码需要大约2分钟,在此期间java.exe也不会被杀死。

long startTime = System.currentTimeMillis(), endTime;
Socket clientSock = new Socket("localhost",80); // running Apache on localhost
endTime = System.currentTimeMillis();
Log("Connection time " + (endTime - startTime) + " ms");
clientSock.close();

run:
Connection time 125088 ms 

对于Java,我做了一些搜索,这个问题是JDK版本1中的一个错误,但更改日志显示它已被修补。但是,这又发生在底层的winsock库中。为什么?该程序立即连接,它也使用winsock:http://flatassembler.net/examples/quetannon.zip

所以现在我必须在程序集中重新编写 976 的JAVA行?帮帮我这里的人。

2 个答案:

答案 0 :(得分:0)

由于您在最终委托给Winsock的多个包装器中遇到相同的问题,因此可以安全地假设这是一个操作系统问题,而不是编码问题。您的系统上有些东西已经安装了Winsock,或者操作系统通常遇到网络问题,特别是因为简单的操作系统重启并没有解决问题。尝试使用Windows的命令行netsh工具重置TCP和Winsock子系统,命令行ipconfig工具以刷新DNS缓存,重新启动,并查看问题是否仍然存在。

在编码方面,您应该在connect()上实施超时以避免进一步的死锁。有两种方法可以做到这一点:

  1. 将套接字置于非阻止模式,然后在select()返回connect()错误时调用WSAEWOULDBLOCk。如果select()超时,请关闭套接字。

  2. 将套接字置于阻塞模式,并使用单独的线程来管理超时。在线程中调用connect(),或在线程中运行超时逻辑,这并不重要,但如果在connect()仍在运行时超时已过,则可以关闭套接字,中止{{1 }}。这是connect()使用的方法。

答案 1 :(得分:0)

确定。对于JAVA部分,我至少通过使用以下代码Java Socket creation takes more time来解决它。

所以基本上默认的超时值是(可能)很大。所以我做的是设置3秒的超时,然后一旦抛出超时异常,下一个调用立即工作。

private static final int CONNECT_TIMEOUT = 3000; // 3 seconds
private static Socket AttemptConnection(String host, int port) {
    Socket temp;
    try {
        temp = new Socket();
        temp.connect(new InetSocketAddress(host, port), CONNECT_TIMEOUT);
        return temp;
    } catch (Exception ex) {
        temp = null;
        lastException = ex.getMessage();
        return temp;
    }
}

代码中的某处(至少在我的应用中)

while ( (clientSock = AttemptConnection("localhost",80)) == null ){
    Log("Attempting connection. Last exception: " + lastException);
    try{Thread.sleep(2500);}catch(Exception ex){} /* This is necessary in my application */
}

所以看看这个我认为所有套接字实现(JAVA,Delphi等)的修复是设置一个小的超时值然后再次连接。

修改

发现了问题的根源:我的笔记本电脑上运行了HIPS程序(COMODO防火墙)。如果COMODO的cmdagent.exe处于活动状态,它会向我显示我可以接受/拒绝的传出连接的警报。如果没有,它会默默地拒绝连接,因此在低级别中会出现问题。我很担心我的电脑会出现问题。