Announcement

Collapse
No announcement yet.

OVERLAPPED SOCKET - Anyone have a working demo?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #21
    I haven't looked at this in a couple of years.

    As I understood it this was supposed to be the "best" way to be able to handle a huge number of TCP sockets.
    My normal way was to start a thread for each socket but Microsoft says this way is much better - way more efficient

    It is like all "overlapped" things in that it will call a completion function when it is ready.

    However I never could get it to work right.

    I could never get the "FUNCTION CompletionROUTINE" to fire...

    You need to have some sort of TCP process trying to connect to play with this.
    I will mess around with it some more and see if I can come up with cleaner version....
    I'll make a "client thing" to use to test this.





    Code:
    #COMPILE EXE
    #DIM ALL
    
    #INCLUDE "Win32API.inc"
    
    
    GLOBAL GL_hDlg AS DWORD
    GLOBAL GL_LOG_FILE_NUMBER AS LONG
    GLOBAL GL_STOP_IT AS LONG
    GLOBAL CompletionPort AS DWORD
    GLOBAL lpOverlapped AS WSAOVERLAPPED
    
    
    ENUM CONTROLS SINGULAR
    ENUM_STARTING_NUMBER = 100
    TIMER_1
    LISTBOX_VIEWER
    TCP_EVENT
    END ENUM
    
    ENUM MESSAGES SINGULAR
    ENUM_STARTING_MESSAGESS_NUMBER = %WM_APP
    WM_SOCKET
    END ENUM
    
    
    DECLARE FUNCTION AcceptEx IMPORT "MSWSOCK.DLL" ALIAS "AcceptEx" ( _
    BYVAL sListenSocket AS DWORD _ ' __in SOCKET sListenSocket
    , BYVAL sAcceptSocket AS DWORD _ ' __in SOCKET sAcceptSocket
    , BYREF lpOutputBuffer AS ANY _ ' __in PVOID lpOutputBuffer
    , BYVAL dwReceiveDataLength AS DWORD _ ' __in DWORD dwReceiveDataLength
    , BYVAL dwLocalAddressLength AS DWORD _ ' __in DWORD dwLocalAddressLength
    , BYVAL dwRemoteAddressLength AS DWORD _ ' __in DWORD dwRemoteAddressLength
    , BYREF lpdwBytesReceived AS DWORD _ ' __out LPDWORD lpdwBytesReceived
    , BYREF lpOverlapped AS OVERLAPPED _ ' __in LPOVERLAPPED lpOverlapped
    ) AS LONG
    
    '------------------------------------------------------------------------------
    FUNCTION PBMAIN () AS LONG
    
    ' local MY_SYSTEM_INFO as SYSTEM_INFO
    ' GetSystemInfo(MY_SYSTEM_INFO)
    ' msgbox format$(MY_SYSTEM_INFO.dwNumberOfProcessors)
    
    MAIN_DIALOG
    MY_WSACleanup
    
    END FUNCTION
    '------------------------------------------------------------------------------
    FUNCTION MAIN_DIALOG() AS LONG
    
    LOCAL RESULT AS LONG
    LOCAL DIALOG_HEIGHT AS LONG
    LOCAL DIALOG_WIDTH AS LONG
    LOCAL DIALOG_STYLE AS LONG
    LOCAL DIALOG_STYLE_EX AS LONG
    LOCAL LISTBOX_STYLE AS LONG
    LOCAL LISTBOX_STYLE_EX AS LONG
    
    DIALOG_HEIGHT = 320
    DIALOG_WIDTH = 575
    
    DIALOG_STYLE = %WS_POPUP OR %WS_CAPTION OR %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_CENTER OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT
    DIALOG_STYLE_EX = %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
    
    LISTBOX_STYLE = %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %WS_VSCROLL OR %LBS_NOTIFY OR %LBS_DISABLENOSCROLL
    LISTBOX_STYLE_EX = %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
    
    DIALOG NEW %HWND_DESKTOP, "WinSock2_Test", 0, 0, DIALOG_WIDTH, DIALOG_HEIGHT, DIALOG_STYLE, DIALOG_STYLE_EX, TO GL_hDlg
    
    CONTROL ADD LISTBOX, GL_hDlg, %LISTBOX_VIEWER,, 10, 10, 575-20, 320-60, LISTBOX_STYLE, LISTBOX_STYLE_EX
    
    DIALOG SHOW MODAL GL_hDlg, CALL MAIN_DIALOG_CALLBACK
    
    END FUNCTION
    '------------------------------------------------------------------------------
    'DECLARE FUNCTION GetQueuedCompletionStatus IMPORT "KERNEL32.DLL" ALIAS "GetQueuedCompletionStatus" ( _
    ' BYVAL CompletionPort AS DWORD _ ' __in HANDLE CompletionPort
    ' , BYREF lpNumberOfBytesTransferred AS DWORD _ ' __out LPDWORD lpNumberOfBytesTransferred
    ' , BYREF lpCompletionKey AS DWORD _ ' __out PULONG_PTR lpCompletionKey
    ' , BYREF lpOverlapped AS DWORD _ ' __out LPOVERLAPPED *lpOverlapped
    ' , BYVAL dwMilliseconds AS DWORD _ ' __in DWORD dwMilliseconds
    ' ) AS LONG ' BOOL
    
    
    CALLBACK FUNCTION MAIN_DIALOG_CALLBACK
    
    SELECT CASE AS LONG CB.MSG
    
    CASE %WM_INITDIALOG
    SETTIMER(GL_hDlg, %TIMER_1, 200)
    
    
    CASE %WM_TIMER
    KILLTIMER(GL_hDlg, %TIMER_1)
    CompletionPort = CreateIoCompletionPort(%INVALID_HANDLE_VALUE, 0, 0, 6)
    'GL_STOP_IT = %TRUE
    START_COMM_THREAD(1)
    'SLEEP 5000
    'GL_STOP_IT = %FALSE
    
    END SELECT
    
    END FUNCTION
    
    '------------------------------------------------------------------------------
    FUNCTION START_COMM_THREAD(THREAD_ID AS LONG)AS LONG
    
    LOCAL THREAD_HANDLE AS LONG
    LOCAL THREAD_RESULT AS LONG
    
    THREAD CREATE THREADED_COMM_THREAD(THREAD_ID) TO THREAD_HANDLE
    THREAD CLOSE THREAD_HANDLE TO THREAD_RESULT
    
    END FUNCTION
    '------------------------------------------------------------------------------
    THREAD FUNCTION THREADED_COMM_THREAD(BYVAL NO_VAL AS LONG)AS LONG
    ON ERROR GOTO ERROR_CONTROL
    
    LOCAL RESULT_LONG AS LONG
    
    LOCAL LISTENING_SOCKET AS DWORD
    LOCAL ACCEPTING_SOCKET AS DWORD
    LOCAL TYPE_SOCKET_ADDRESS AS sockaddr_in
    
    LOCAL nBytesReceived AS LONG
    LOCAL nFlags AS LONG
    
    LOCAL MY_WSAOVERLAPPED AS WSAOVERLAPPED
    LOCAL MY_WSAPROTOCOL_INFOA AS WSAPROTOCOL_INFOA
    
    LOCAL MY_WSADATA AS WSADATA
    LOCAL WSARecv_Error AS LONG
    
    'TYPE WSABUF DWORD
    ' dLen AS DWORD ' the length of the buffer
    ' buf AS BYTE PTR ' the pointer to the buffer
    'END TYPE
    
    LOCAL wsBuf AS WSABUF
    
    ' local CompletionPort as dword
    
    ' CompletionPort = CreateIoCompletionPort(%INVALID_HANDLE_VALUE, byval 0, 0, 0)
    
    
    'The WSAStartup function initiates use of the Winsock DLL by a process.
    RESULT_LONG = WSAStartup(MAKWRD(2, 2), MY_WSADATA)
    
    'The WSASocket function creates a socket that is bound to a specific transport-service provider.
    LISTENING_SOCKET = WSASocket(%AF_INET, %SOCK_STREAM, %IPPROTO_TCP, BYVAL 0, 0, %WSA_FLAG_OVERLAPPED)
    
    'Set up the sock addr structure that the listening socket will be bound to. In this case, the structure holds the local IP address and the port.
    TYPE_SOCKET_ADDRESS.sin_family = %AF_INET
    TYPE_SOCKET_ADDRESS.sin_port = htons(4070)
    TYPE_SOCKET_ADDRESS.sin_addr.s_addr = inet_addr("192.168.1.193") 'or htonl(%INADDR_ANY)
    
    
    'The bind function associates a local address with a socket. Bind the listening socket to the IP address and port.
    RESULT_LONG = bind(LISTENING_SOCKET, BYVAL VARPTR(TYPE_SOCKET_ADDRESS), SIZEOF(TYPE_SOCKET_ADDRESS))
    
    'The listen function places a socket in a state in which it is listening for an incoming connection.
    RESULT_LONG = listen(LISTENING_SOCKET, 5)
    
    
    TEXT_TO_SCREEN "IM WAITING FOR THE LISTENING SOCKET TO BE CONTACTED BY SOMEONE WANTING TO COMMUNICATE"
    'ACCEPTING_SOCKET = WSAAccept(LISTENING_SOCKET, BYVAL VARPTR(TYPE_SOCKET_ADDRESS), SIZEOF(TYPE_SOCKET_ADDRESS), 0, 0)
    
    
    ACCEPTING_SOCKET = WSASocket(%AF_INET, %SOCK_STREAM, %IPPROTO_TCP, BYVAL 0, 0, %WSA_FLAG_OVERLAPPED)
    TEXT_TO_SCREEN "ACCEPTING_SOCKET = " + FORMAT$(ACCEPTING_SOCKET)
    
    
    LOCAL my_bytes AS DWORD
    LOCAL AcceptBuffer AS ASCIIZ *48
    
    
    
    DIM MY_ARRAY(9) AS DWORD
    MY_ARRAY(0) = WSACreateEvent() 'CreateEvent(byval 0, %TRUE, %FALSE, "Event_1")
    
    
    MY_WSAOVERLAPPED.hEvent = MY_ARRAY(0)
    TEXT_TO_SCREEN "MY_WSAOVERLAPPED.hEvent = " + FORMAT$(MY_ARRAY(0))
    
    
    
    
    RESULT_LONG = AcceptEx(LISTENING_SOCKET, ACCEPTING_SOCKET, AcceptBuffer, 0, 48,48, My_bytes, MY_WSAOVERLAPPED)
    
    TEXT_TO_SCREEN "ACCEPT = " + (FORMAT$(WSAGetLastError))
    
    TEXT_TO_SCREEN "ACCEPTING_SOCKET = " + FORMAT$(ACCEPTING_SOCKET)
    
    TEXT_TO_SCREEN "ACCEPTING_SOCKET " + FORMAT$(WSAGetLastError) + " - " + FORMAT$(ACCEPTING_SOCKET)
    
    LOCAL PTR_IP_ADDRESS AS BYTE POINTER
    PTR_IP_ADDRESS = VARPTR(TYPE_SOCKET_ADDRESS.sin_addr)
    
    TEXT_TO_SCREEN "CONNECTED IP = " + USING$("#_.#_.#_.#", @PTR_IP_ADDRESS, @PTR_IP_ADDRESS[1], @PTR_IP_ADDRESS[2], @PTR_IP_ADDRESS[3])
    winbeep(500,500)
    
    
    
    
    'WSAResetEvent 'The WSAResetEvent function resets the state of the specified event object to nonsignaled.
    'The WSASetEvent function sets the state of the specified event object to signaled.
    
    
    
    LOCAL my_pointer AS ASCIIZ POINTER
    LOCAL my_asciiz AS ASCIIZ *4096
    my_pointer = VARPTR(my_asciiz)
    wsBuf.dLen = 4096
    wsBuf.buf = my_pointer
    
    
    
    
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.Internal)
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.InternalHigh)
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.offset)
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.OffsetHigh)
    TEXT_TO_SCREEN "H " + FORMAT$(MY_WSAOVERLAPPED.hEvent)
    
    
    TEXT_TO_SCREEN "NEXT LINE = WSAWaitForMultipleEvents"
    RESULT_LONG = WSAWaitForMultipleEvents(1, BYVAL VARPTR(MY_ARRAY(0)), %FALSE, 8000, %FALSE)
    
    TEXT_TO_SCREEN "NEXT LINE = WSARecv"
    RESULT_LONG = WSARecv(ACCEPTING_SOCKET, wsBuf, 1, 0, nFlags, MY_WSAOVERLAPPED, 0)
    WSARecv_Error = WSAGetLastError
    
    IF WSARecv_Error = 997 THEN
    TEXT_TO_SCREEN "Error 997 - I think this is good as it means an Overlapped I/O operation is in progress.
    ELSE
    TEXT_TO_SCREEN "Last Error = " + FORMAT$(WSAGetLastError)
    END IF
    
    TEXT_TO_SCREEN "---> " + FORMAT$(nBytesReceived) + " - " + my_asciiz
    
    TEXT_TO_SCREEN "DONE"
    
    EXIT FUNCTION
    
    
    
    
    
    
    DO WHILE ISWIN(GL_hDlg)
    TEXT_TO_SCREEN "do"
    
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.Internal)
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.InternalHigh)
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.offset)
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.OffsetHigh)
    TEXT_TO_SCREEN FORMAT$(MY_WSAOVERLAPPED.hEvent)
    
    WSAResetEvent MY_WSAOVERLAPPED.hEvent
    
    RESULT_LONG = WSAWaitForMultipleEvents(1, VARPTR(MY_ARRAY(0)), %FALSE, 2000, %FALSE)
    
    
    
    'TEXT_TO_SCREEN FORMAT$(WSAGetLastError)
    'WSAResetEvent(MY_WSAOVERLAPPED.hEvent)
    'TEXT_TO_SCREEN FORMAT$(WSAGetLastError)
    
    LOCAL Flags AS DWORD
    RESULT_LONG = WSAGetOverlappedResult(ACCEPTING_SOCKET, MY_WSAOVERLAPPED, nBytesReceived, %FALSE, Flags)
    
    RESULT_LONG = WSARecv(ACCEPTING_SOCKET, wsBuf, 1, nBytesReceived, nFlags, MY_WSAOVERLAPPED, 0)
    
    
    WEND
    
    
    
    EXIT FUNCTION
    
    ERROR_CONTROL:
    MSGBOX ERROR$
    
    END FUNCTION
    '------------------------------------------------------------------------------
    FUNCTION CompletionROUTINE(dwError AS DWORD, cbTransferred AS DWORD, lpOverlapped AS WSAOVERLAPPED, dwFlags AS DWORD)AS LONG
    
    MSGBOX "CompletionROUTINE"
    
    END FUNCTION
    '------------------------------------------------------------------------------
    FUNCTION MY_WSACleanup()AS LONG
    
    WSACleanup
    IF WSACleanup = 0 THEN TEXT_TO_SCREEN "WSACleanup"
    
    END FUNCTION
    '------------------------------------------------------------------------------
    FUNCTION TEXT_TO_SCREEN (TEXT_STRING AS STRING) AS LONG
    LOCAL LISTBOX_COUNT AS LONG
    
    LISTBOX ADD GL_hDlg, %LISTBOX_VIEWER, " " + TEXT_STRING
    LISTBOX GET COUNT GL_hDlg, %LISTBOX_VIEWER TO LISTBOX_COUNT
    CONTROL SEND GL_hDlg, %LISTBOX_VIEWER, %LB_SETTOPINDEX, LISTBOX_COUNT-1, 0
    END FUNCTION
    '------------------------------------------------------------------------------

    Comment

    Working...
    X