同时处理多个连接的最佳方法

时间:2014-03-11 22:47:48

标签: sockets networking vb6 window connection

我有一个应用程序,它可以侦听多个连接并验证用户是否处于活动状态

我使用WSAASyncSelect的1线程套接字处理方法。

问题在于,有时当很多用户同时连接某些用户时没有得到回复

我认为这是因为"发送"尚未被调用,程序已收到另一个连接,因此它再次处理新连接而忽略前一个连接。就像WSAASyncSelect已触发,现在它处理新连接而不是完成上一个请求。

那么如何解决这个问题呢?我试图通过在处理连接时使用零参数调用事件来暂停WSAASyncSelect临时事件,直到完成它然后重新启用网络事件但是没有帮助。

以下是处理事件的代码(接收然后解密,然后比较字节,然后根据列表框中的内容发送数据,即是否为活动用户)

这需要收到FD_READ

WSAAsyncSelect s, frmMain.hwnd, 0, 0 'Disabling Notifications event

Do Until bytesRecieved = SOCKET_ERROR
    bytesRecieved = recv(wParam, buffer(Bytes), 500, 0)
    If bytesRecieved > 0 Then
        Bytes = Bytes + bytesRecieved


    ElseIf bytesRecieved = 0 Then
        Exit Sub
    End If
Loop
Call MemCopy(ByVal decryptedArrival, buffer(0), Bytes)

WSAAsyncSelect s, frmMain.hwnd, WINSOCKMSG, FD_CONNECT + FD_READ + FD_CLOSE + FD_ACCEPT + FD_WRITE

If frmMain.chkSaveLog.value = vbChecked Then
    frmMain.txtConnectionsLog.Text = frmMain.txtConnectionsLog.Text & Now & " Receiving a connection (" & wParam & ")" & vbNewLine
    AutoScroll
    If frmMain.chkAutoSave.value = vbChecked Then
        strCurrentLogLine = Now & " Receiving a connection (" & wParam & ")"
        AutoSaveLog (strCurrentLogLine)
        frmMain.cmdClearLogs.Enabled = True
    End If
End If

下面是字节解密,然后通过ID比较字节标识符,如1 =检查更新 2 - 发送用户信息等

在发送Api之后的Select Case语句中。

接受程序

这要求收到FD_ACCEPT

Function AcceptConnection(wParam As Long)

lpString = String(32, 0)


        AcSock = accept(wParam, sockaddress, Len(sockaddress))

        strTempIP = getascip(sockaddress.sin_addr)


        frmMain.txtConnectionsLog.Text = frmMain.txtConnectionsLog.Text & Now & " Getting a connection from IP address: " & _
        strTempIP & " (" & AcSock & ")" & vbNewLine
        AutoScroll
        If frmMain.chkAutoSave.value = vbChecked Then
         strCurrentLogLine = Now & " Getting a connection from IP address: " & strTempIP & " (" & AcSock & ")" & vbNewLine
          AutoSaveLog (strCurrentLogLine)
        End If

End Function

对于更好的表现有什么建议吗?

2 个答案:

答案 0 :(得分:2)

您展示的内容不是使用WSAAsyncSelect()的正确方法。尝试更像这样的东西:

创建侦听套接字时:

lSock = socket(...)
bind(lSock, ...)
listen(lSock, ...)
WSAAsyncSelect lSock, frmMain.hwnd, WINSOCKMSG, FD_ACCEPT

当侦听套接字收到FD_ACCEPT时:

Function AcceptConnection(wParam As Long)

  AcSock = accept(wParam, sockaddress, Len(sockaddress))
  If AcSock = INVALID_SOCKET Then
    Exit Sub
  End If

  WSAAsyncSelect AcSock, frmMain.hwnd, WINSOCKMSG, FD_READ + FD_CLOSE + FD_WRITE

  ...

End Function

当接受的客户端套接字收到FD_READ时:

Function ReadConnection(wParam As Long)

  Do
    bytesRecieved = recv(wParam, ReadBuffer(ReadBytes), 500, 0)
    If bytesRecieved = SOCKET_ERROR Then
      If WSAGetLastError() <> WSAEWOULDBLOCK Then
        Exit Sub
      End If
    ElseIf bytesRecieved = 0 Then
      Exit Sub
    Else
      ReadBytes = ReadBytes + bytesRecieved
    End If
  Loop Until bytesRecieved = SOCKET_ERROR

  ' process ReadBuffer up to ReadBytes number of bytes as needed...
  ' remove processed bytes from front of ReadBuffer and decrement ReadBytes accordingly

  ...

End Function

当接受的客户端套接字收到FD_WRITE时:

函数WriteConnection(wParam As Long)

SendBytes&gt; 0     bytesSent = send(wParam,SendBuffer(0),SendBytes,0)     如果bytesSent = SOCKET_ERROR那么       退出子     万一     &#39;从SendBuffer前面删除bytesSent字节数...     SendBytes = SendBytes - bytesSent;   结束时

结束功能

诀窍是您需要为每个接受的客户端分配单独的 ReadBufferSendBuffer缓冲区。确保每次收到FD_READ时,您只将字节附加到触发ReadBuffer的套接字的FD_READ,并且每次收到FD_WRITE时,您要删除仅来自触发SendBuffer的套接字的FD_WRITE的字节。

recv()没有更多字节需要阅读时,根据需要处理该套接字ReadBuffer,只删除前面的完整邮件,留下不完整的邮件供以后处理。

send()WSAEWOULDBLOCK失败时,将任何未发送的字节附加到导致SendBuffer失败的套接字的send()。当您收到套接字的FD_WRITE事件时,请检查该套接字SenBuffer并重新发送其中的所有字节,在buffer耗尽或{{1}时停止发生错误。

答案 1 :(得分:0)

非常简单且非常有效的方法是为每个传入连接分叉。这很可能需要您重新构建应用程序,但基本流程应如下所示: 1.向服务器打开新连接 2.服务器接受连接并分叉 3. fork关闭原始套接字以进行侦听,因此只有父级接受新连接 然后你的魔法发生了,与原始线程分开。

这样您就不必担心并发问题,只要您的计算机可以处理所有流量和负载,因为每个连接都是独立的。