AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Client & Server Script for TCP/IP Network Communication
Goto page Previous  1, 2, 3, 4, 5, 6, 7  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Lexikos



Joined: 17 Oct 2006
Posts: 2602
Location: Australia, Qld

PostPosted: Mon Mar 31, 2008 10:24 pm    Post subject: Reply with quote

Quote:
The inet_addr function converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for the IN_ADDR structure.
You should be able to manually fill SocketAddress with a sockaddr_in6 structure. The definition is:
Code:
typedef struct sockaddr_in6 {
    ADDRESS_FAMILY sin6_family; // AF_INET6.
    USHORT sin6_port;           // Transport level port number.
    ULONG  sin6_flowinfo;       // IPv6 flow information.
    IN6_ADDR sin6_addr;         // IPv6 address.
    union {
        ULONG sin6_scope_id;     // Set of interfaces for a scope.
        SCOPE_ID sin6_scope_struct;
    };
} SOCKADDR_IN6_LH, *PSOCKADDR_IN6_LH, FAR *LPSOCKADDR_IN6_LH;

typedef struct in6_addr {
    union {
        UCHAR       Byte[16];
        USHORT      Word[8];
    } u;
} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR;
Back to top
View user's profile Send private message
IsNull



Joined: 10 May 2007
Posts: 72
Location: .switzerland

PostPosted: Wed Apr 02, 2008 7:37 am    Post subject: Reply with quote

thx I will try this.
_________________
http://securityvision.ch
Back to top
View user's profile Send private message
LYCOS17



Joined: 06 Feb 2008
Posts: 20
Location: Dallas

PostPosted: Mon Apr 21, 2008 2:04 am    Post subject: Reply with quote

Hi there, I have been working with this code a bit and had a weird question, .... the problem was the script kept crashing when I close the client script, but if I just did a re-load on the client script the problem goes away.... so thanks very much (!) to the other poster aka. someotherguy who helped me by giving me this _obvious_ clue! Very Happy

Last edited by LYCOS17 on Thu May 01, 2008 10:22 am; edited 4 times in total
Back to top
View user's profile Send private message
LYCOS17



Joined: 06 Feb 2008
Posts: 20
Location: Dallas

PostPosted: Wed Apr 30, 2008 3:48 pm    Post subject: Reply with quote

*bump*

Last edited by LYCOS17 on Thu May 01, 2008 10:17 am; edited 1 time in total
Back to top
View user's profile Send private message
Z Gecko
Guest





PostPosted: Wed Apr 30, 2008 8:03 pm    Post subject: Reply with quote

I am no expert a t this, so i have no general idea.

But if you post your try and the errormessages you get,
it might be easier to analyze that problem.
Back to top
CraSH23000



Joined: 22 Jun 2007
Posts: 38

PostPosted: Wed Apr 30, 2008 9:09 pm    Post subject: Reply with quote

Thanks a lot for this Zed Gecko, this looks awesome, and thanks LYCOS17 for bumping because I would have never seen this, lol.
_________________
What is real in our infinitely alternating perception of reality?
Back to top
View user's profile Send private message
CraSH23000



Joined: 22 Jun 2007
Posts: 38

PostPosted: Fri May 02, 2008 6:35 am    Post subject: Reply with quote

Hi,
I was trying to combine qtmspin's code that allowed multiple users and wtg's code that sent the text to an edit box. I get an error when I send:


(if they take that down, go here http://crash23000.freewebspace.com/TCP_error.JPG

As you can see, it sends the data and works for multiple clients, but still displays an error on send.

Heres the code

Server:
Code:
; -------------------------------------------------
; ------------SERVERSCRIPT------------------
; -------------------------------------------------
; CONFIGURATION SECTION:

; Specify Your own Network's address and port.
Network_Address = 127.0.0.1
Network_Port = 8765
; ----------------------------
; END OF CONFIGURATION SECTION
; ----------------------------

Gui, Add, Text,, Send:
Gui, Add, Edit, w100 vSendText
Gui, Add, Text,, Repeat:
Gui, Add, Edit, w40 vRepeat, 1
Gui, Add, Text,, Delay (ms):
Gui, Add, Edit, w40 vDelay, 0   
Gui, Add, Button, gSendviaNet, Send
Gui, Show

Gosub Connection_Init
return

Connection_Init:
OnExit, ExitSub  ; For connection cleanup purposes.

; set up a very basic server:
socket := PrepareForIncomingConnection(Network_Address, Network_Port)
if socket = -1  ; Connection failed (it already displayed the reason).
    ExitApp

; Find this script's main window:
Process, Exist  ; This sets ErrorLevel to this script's PID (it's done this way to support compiled scripts).
DetectHiddenWindows On
ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
DetectHiddenWindows Off

; Set up the connection to notify this script via message whenever new data has arrived.
; This avoids the need to poll the connection and thus cuts down on resource usage.
FD_READ = 1     ; Received when data is available to be read.
;FD_WRITE =
FD_CLOSE = 32   ; Received when connection has been closed.
FD_CONNECT = 20 ; Received when connection has been made.
if DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket, "UInt", ScriptMainWindowId, "UInt", NotificationMsg, "Int", FD_CLOSE|FD_CONNECT)
{
    MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
    ExitApp
}


i=1
Loop ; Wait for incomming connections
{
; accept requests that are in the pipeline of the socket   
   conectioncheck%i% := DllCall("Ws2_32\accept", "UInt", socket, "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
; Ws2_22/accept returns the new Connection-Socket if a connection request was in the pipeline
; on failure it returns an negative value
    if conectioncheck%i% > 1
    {
       MsgBox Incoming connection accepted
       i++
    }       
    sleep 500 ; wait half 1 second then accept again
}   
return

SendviaNet:
Gui, Submit, NoHide
Loop %i% {
SendData(conectioncheck%A_Index%,SendText,Repeat,Delay)
}
SentText =
return

PrepareForIncomingConnection(IPAddress, Port)
; This can connect to most types of TCP servers, not just Network.
; Returns -1 (INVALID_SOCKET) upon failure or the socket ID upon success.
{
    VarSetCapacity(wsaData, 32)  ; The struct is only about 14 in size, so 32 is conservative.
    result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData) ; Request Winsock 2.0 (0x0002)
    ; Since WSAStartup() will likely be the first Winsock function called by this script,
    ; check ErrorLevel to see if the OS has Winsock 2.0 available:
    if ErrorLevel
    {
        MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
        return -1
    }
    if result  ; Non-zero, which means it failed (most Winsock functions return 0 upon success).
    {
        MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }

    AF_INET = 2
    SOCK_STREAM = 1
    IPPROTO_TCP = 6
    socket := DllCall("Ws2_32\socket", "Int", AF_INET, "Int", SOCK_STREAM, "Int", IPPROTO_TCP)
    if socket = -1
    {
        MsgBox % "socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }

    ; Prepare for connection:
    SizeOfSocketAddress = 16
    VarSetCapacity(SocketAddress, SizeOfSocketAddress)
    InsertInteger(2, SocketAddress, 0, AF_INET)   ; sin_family
    InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)   ; sin_port
    InsertInteger(DllCall("Ws2_32\inet_addr", "Str", IPAddress), SocketAddress, 4, 4)   ; sin_addr.s_addr

    ; Bind to socket:
    if DllCall("Ws2_32\bind", "UInt", socket, "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
    {
        MsgBox % "bind() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") . "?"
        return -1
    }
    if DllCall("Ws2_32\listen", "UInt", socket, "UInt", "SOMAXCONN")
    {
        MsgBox % "LISTEN() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") . "?"
        return -1
    }
   
    return socket  ; Indicate success by returning a valid socket ID rather than -1.
}

SendData(wParam,SendData, Repeat, Delay)
{
   socket := wParam
;   SendDataSize := VarSetCapacity(SendData)
;   SendDataSize += 1
   Loop % Repeat
   {
        SendIt := SendData  ;SendIt := SendData . "(" . A_Index . ")"
      SendDataSize := VarSetCapacity(SendIt)
      SendDataSize += 1
     
      sendret := DllCall("Ws2_32\send", "UInt", socket, "Str", SendIt, "Int", SendDatasize, "Int", 0)
      WinsockError := DllCall("Ws2_32\WSAGetLastError")
      if WinsockError <> 0 ; WSAECONNRESET, which happens when Network closes via system shutdown/logoff.
         ; Since it's an unexpected error, report it.  Also exit to avoid infinite loop.
         MsgBox % "send() indicated Winsock error " . WinsockError
        sleep,Delay
   }     
;send( sockConnected,> welcome, strlen(welcome) + 1, NULL);
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; The caller must ensure that pDest has sufficient capacity.  To preserve any existing contents in pDest,
; only pSize number of bytes starting at pOffset are altered in it.
{
    Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
        DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

guiclose:
ExitSub:  ; This subroutine is called automatically when the script exits for any reason.
; MSDN: "Any sockets open when WSACleanup is called are reset and automatically
; deallocated as if closesocket was called."
DllCall("Ws2_32\WSACleanup")
ExitApp


Client:
Code:
; -------------------------------------------------
;-----------CLIENTSCRIPT----------------------
; -------------------------------------------------
; CONFIGURATION SECTION:

; Specify address and port of the server.
Network_Address = 127.0.0.1
Network_Port = 8765
; ----------------------------
; END OF CONFIGURATION SECTION
; ----------------------------

Gui, Add, Button, gConnection_Init, Connect
Gui, Add, Edit, R10 vMyEdit
Gui, Add, Button, gClear, Clear
Gui, Show

LinesReceived:=0
return

Connection_Init:
OnExit, ExitSub  ; For connection cleanup purposes.

; Connect to any type of server:
socket := ConnectToAddress(Network_Address, Network_Port)
if socket = -1  ; Connection failed (it already displayed the reason).
    ExitApp

; Find this script's main window:
Process, Exist  ; This sets ErrorLevel to this script's PID (it's done this way to support compiled scripts).
DetectHiddenWindows On
ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
DetectHiddenWindows Off

; When the OS notifies the script that there is incoming data waiting to be received,
; the following causes a function to be launched to read the data:
NotificationMsg = 0x5555  ; An arbitrary message number, but should be greater than 0x1000.
OnMessage(NotificationMsg, "ReceiveData")

; Set up the connection to notify this script via message whenever new data has arrived.
; This avoids the need to poll the connection and thus cuts down on resource usage.
FD_READ = 1     ; Received when data is available to be read.
FD_CLOSE = 32   ; Received when connection has been closed.
if DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket, "UInt", ScriptMainWindowId, "UInt", NotificationMsg, "Int", FD_READ|FD_CLOSE)
{
    MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
    ExitApp
}
return

Clear:
ShowReceived=
LinesReceived:=0   
GuiControl,, MyEdit,
return

ConnectToAddress(IPAddress, Port)
; Returns -1 (INVALID_SOCKET) upon failure or the socket ID upon success.
{
    VarSetCapacity(wsaData, 32)  ; The struct is only about 14 in size, so 32 is conservative.
    result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData) ; Request Winsock 2.0 (0x0002)
    ; Since WSAStartup() will likely be the first Winsock function called by this script,
    ; check ErrorLevel to see if the OS has Winsock 2.0 available:
    if ErrorLevel
    {
        MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
        return -1
    }
    if result  ; Non-zero, which means it failed (most Winsock functions return 0 upon success).
    {
        MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }

    AF_INET = 2
    SOCK_STREAM = 1
    IPPROTO_TCP = 6
    socket := DllCall("Ws2_32\socket", "Int", AF_INET, "Int", SOCK_STREAM, "Int", IPPROTO_TCP)
    if socket = -1
    {
        MsgBox % "socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }

    ; Prepare for connection:
    SizeOfSocketAddress = 16
    VarSetCapacity(SocketAddress, SizeOfSocketAddress)
    InsertInteger(2, SocketAddress, 0, AF_INET)   ; sin_family
    InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)   ; sin_port
    InsertInteger(DllCall("Ws2_32\inet_addr", "Str", IPAddress), SocketAddress, 4, 4)   ; sin_addr.s_addr

    ; Attempt connection:
    if DllCall("Ws2_32\connect", "UInt", socket, "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
    {
        MsgBox % "connect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") . "?"
        return -1
    }
    return socket  ; Indicate success by returning a valid socket ID rather than -1.
}

ReceiveData(wParam, lParam)
; By means of OnMessage(), this function has been set up to be called automatically whenever new data
; arrives on the connection.
{
     Critical
    global ShowReceived
    global MyEdit
    global LinesReceived

    socket := wParam
    ReceivedDataSize = 4096  ; Large in case a lot of data gets buffered due to delay in processing previous data.
    VarSetCapacity(ReceivedData, ReceivedDataSize, 0)  ; 0 for last param terminates string for use with recv().
    Data   := ""
    Loop  ; This loop solves the issue of the notification message being discarded due to thread-already-running.
    {
        ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", socket, "Str", ReceivedData, "Int", ReceivedDataSize, "Int", 0)
        if ReceivedDataLength = 0  ; The connection was gracefully closed,
            ExitApp  ; The OnExit routine will call WSACleanup() for us.
        if ReceivedDataLength = -1
        {
            WinsockError := DllCall("Ws2_32\WSAGetLastError")
            if ( WinsockError = 10035 ) { ; WSAEWOULDBLOCK, which means "no more data to be read".
                break
            }
            if WinsockError <> 10054 ; WSAECONNRESET, which happens when Network closes via system shutdown/logoff.
                ; Since it's an unexpected error, report it.  Also exit to avoid infinite loop.
                MsgBox % "recv() indicated Winsock error " . WinsockError
            ExitApp  ; The OnExit routine will call WSACleanup() for us.
        }
        Data .= ReceivedData
    }
    ; Otherwise, process the data received.
    Loop, parse, Data, `n, `r
    {
       LinesReceived++               
        if (LinesReceived = 1) {
           ShowReceived = %LinesReceived%: %A_LoopField%
        } else {
           ShowReceived = %ShowReceived%`n%LinesReceived%: %A_LoopField%
       }
       ;Tooltip % ShowReceived
       GuiControl,, MyEdit, %ShowReceived%
    }
    return 1  ; Tell the program that no further processing of this message is needed.
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; The caller must ensure that pDest has sufficient capacity.  To preserve any existing contents in pDest,
; only pSize number of bytes starting at pOffset are altered in it.
{
    Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
        DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

guiclose:
ExitSub:  ; This subroutine is called automatically when the script exits for any reason.
; MSDN: "Any sockets open when WSACleanup is called are reset and automatically
; deallocated as if closesocket was called."
DllCall("Ws2_32\WSACleanup")
ExitApp


I guess I could comment out the error report since it works anyways, unless it is a serious error, but seems like it isn't because it still sends. I was thinking that it is trying to send to someone who isn't connected but I guess I can't interpret the code good enough to verify my assumptions : / lol.


Thanks for any help
_________________
What is real in our infinitely alternating perception of reality?
Back to top
View user's profile Send private message
Z Gecko
Guest





PostPosted: Fri May 02, 2008 7:08 am    Post subject: Reply with quote

since Winsock Error 10038 means Socket operation on non-socket.
Quote:
WSAENOTSOCK
(10038)
Socket operation on non-socket.
An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.


You could be right with your assumption:
Quote:
I was thinking that it is trying to send to someone who isn't connected


maybe it just happens after at least one client disconnected?
could you check this out?
Back to top
CraSH23000



Joined: 22 Jun 2007
Posts: 38

PostPosted: Fri May 02, 2008 7:43 am    Post subject: Reply with quote

The screenshot I took was the server sending "hey" after one client connected, with no disconnects. So I dont think that this is caused by a client disconnecting.

I'm just making another assumption, but I think it has something to do with the code I changed to allow multi-clients.

maybe, either here:
Code:
i=1
Loop ; Wait for incomming connections
{
; accept requests that are in the pipeline of the socket   
   conectioncheck%i% := DllCall("Ws2_32\accept", "UInt", socket, "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
; Ws2_22/accept returns the new Connection-Socket if a connection request was in the pipeline
; on failure it returns an negative value
    if conectioncheck%i% > 1
    {
       MsgBox Incoming connection accepted
       i++
    }       
    sleep 500 ; wait half 1 second then accept again
}   
return

or maybe here:
Code:
SendviaNet:
Gui, Submit, NoHide
Loop %i% {
SendData(conectioncheck%A_Index%,SendText,Repeat,Delay)
}
SentText =
return


I'm guessing that its in one of the spots above, because its the only part of the sending code I changed I think.
_________________
What is real in our infinitely alternating perception of reality?
Back to top
View user's profile Send private message
Z Gecko
Guest





PostPosted: Fri May 02, 2008 8:22 am    Post subject: Reply with quote

i think i got it.
Code:
SendviaNet:
Gui, Submit, NoHide
Loop % i - 1
{
SendData(conectioncheck%A_Index%,SendText,Repeat,Delay)
}
SentText =
return
will fix it.

the var "i" is 2 when one client is accepted,
so in the sending loop, the last iteration will fail.
Back to top
CraSH23000



Joined: 22 Jun 2007
Posts: 38

PostPosted: Fri May 02, 2008 8:54 am    Post subject: Reply with quote

Thanks a lot, this works great, I tried i=0 instead of the i=1 for the 1st part of code I pasted, I should have tried something similar on the 2nd part of code that you fixed, lol.

Thanks a lot though.
_________________
What is real in our infinitely alternating perception of reality?
Back to top
View user's profile Send private message
Burn2
Guest





PostPosted: Sat May 03, 2008 1:06 pm    Post subject: Reply with quote

Hi,

Is it possible to create username and password checker at server side that received from client?
Back to top
Z Gecko
Guest





PostPosted: Sat May 03, 2008 1:32 pm    Post subject: Reply with quote

I´m not shure what you mean, if you mean to have
the client script send a username and a password to the serverscript,
and the serverscript to cancel the connection when they are wrong.
Then yes, it´s pssible. Cool
Back to top
FredMcGary
Guest





PostPosted: Wed May 14, 2008 6:06 am    Post subject: Reply with quote

Like the script got a question.I wanted to know if there was anyway to identify the connections coming in. Like associating the incoming socket of the person trying to connect with their IP address. I was trying to make a sort of chat server if you will and in order to make a effective user list, I needed to associate incoming connections with their network address. This way I can slap a nickname on that address and bam the list will work. Also so when the person disconnects it will show their address disconnecting.

I also noticed on that new Close message that Zed posted were he didn't know if it worked or not, when I attempted to add the functions in the script, only 1 of the 2 dll calls (right after the

Code:

FD_READ = 1     ; Received when data is available to be read.
FD_CLOSE = 32   ; Received when connection has been closed.
FD_CONNECT = 20 ; Received when connection has been made.
)
would work. In terms, I could either be notified that the client was disconnecting OR receive the text they send.
Back to top
Zed Gecko



Joined: 23 Sep 2006
Posts: 98

PostPosted: Mon May 19, 2008 6:10 am    Post subject: Reply with quote

Well, i found out, that the getpeername function of Winsock will return the IP-Address of the socket.
But i neither know how to call it properly via DLL-Call, nor do i know how to handle the the struct that is returned.
(Maybe this is helpfull: http://www.autohotkey.com/forum/viewtopic.php?t=27644 )

For the WSASyncSelect problem, i would like to point you to ManaUsers
TCP/Ip Remote-Script, where he shows, how to do it right.

I also want to note, that Zippo() has crated an network-script that can be include, in his C4-Game-script
_________________
1) All my code can be reused in ANY way. 2) Please check the help and the forum-search, before posting questions; the answer is out there...
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page Previous  1, 2, 3, 4, 5, 6, 7  Next
Page 5 of 7

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group