Sign in to follow this  
Followers 0
corl455

Networking program help (TCP)

4 posts in this topic

#1 ·  Posted (edited)

Alright, so I thought I'd learn a little bit more about network communications in programing, so I wrote two programs (server & client), where the server executes a command sent by the client. So with the help of some of the examples I got the program to work, but, after the client disconnects (just closes the program), if the client trys to reconnect, you can, but none of the commands works. How would I fix this? Also, are there way's of optimizing this to use less CPU. From what I can tell it's not using much, but I haven't throughly tested it yet.

here is my server code:

Opt('MustDeclareVars', 1)
Opt('TrayIconHide', 1)

Main()

Func Main()
    local $file = FileOpen("sev.txt", 0)

    If $file = -1 Then
        filewrite( "sev.txt", inputbox( "Server", "Please input the name of the server pc"))
        Exit
    EndIf
    local $char = FileRead($file)
    FileClose($file)
    
    local $IP = TCPNameToIP($char)
    Local $szIPADDRESS = $IP
    Local $nPORT = 33891
    Local $MainSocket, $GOOEY, $edit, $ConnectedSocket, $szIP_Accepted
    Local $msg, $recv

    TCPStartup()

    $MainSocket = TCPListen($szIPADDRESS, $nPORT)
    
    If $MainSocket = -1 Then Exit
    $ConnectedSocket = -1

    Do
        $ConnectedSocket = TCPAccept($MainSocket)
    Until $ConnectedSocket <> -1

    $szIP_Accepted = SocketToIP($ConnectedSocket)

    While 1
        $recv = TCPRecv($ConnectedSocket, 2048)
        execute($recv)
    WEnd


   

    TCPShutdown()
EndFunc   


Func SocketToIP($SHOCKET)
    Local $sockaddr, $aRet
    
    $sockaddr = DllStructCreate("short;ushort;uint;char[8]")

    $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
            "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
    If Not @error And $aRet[0] = 0 Then
        $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
        If Not @error Then $aRet = $aRet[0]
    Else
        $aRet = 0
    EndIf

    $sockaddr = 0

    Return $aRet
EndFunc

And here is my Client:

#include <GUIConstantsEx.au3>
Opt('MustDeclareVars', 1)

Main()
TCPShutdown()

Func Main()
    Local $ConnectedSocket, $szData, $szIPADDRESS
    Local $nPORT = 33891
    TCPStartup()
    local $ip = msgbox( 4, "Client", "Do you want to use NameToIP?")
    if $ip = 6 Then
        local $g = InputBox(" ", "Please input PC name")
        $szIPADDRESS = TCPNameToIP($g)
    else
        $szIPADDRESS = InputBox( "Input IP", "Please input the IP of the server", "127.0.0.1")
    EndIf
    $ConnectedSocket = -1
    $ConnectedSocket = TCPConnect($szIPADDRESS, $nPORT)


    If @error Then
        MsgBox(4112, "Error", "TCPConnect failed with WSA error: " & @error)
    Else
        While 1
         $szData = InputBox("Data for Server", @LF & @LF & "Enter data to transmit to the SERVER:")
         if @error Or $szData = "" Then ExitLoop
         TCPSend($ConnectedSocket, $szData)
             If @error Then ExitLoop
        WEnd
    EndIf
EndFunc

Any improvements or suggestions are welcome. I wrote this pretty quickly.

EDIT:

yes, there are a few remains from the example programs, and unnecessary variable declarations, I haven't completely cleaned it up.

Edited by corl455

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

The main problem - only being able to connect the first time - is due to your server script being forever stuck in the TCPRecv() loop after someone connects. Even if they disconnect, there's nothing to kick the server back out of there.

A quick fix might be something like this:

TCPStartup()

    $MainSocket = TCPListen($IP, $nPORT)
    
    If $MainSocket = -1 Then Exit

    While 1
        $ConnectedSocket = -1
        
        Do
            $ConnectedSocket = TCPAccept($MainSocket)
            Sleep(50)
        Until $ConnectedSocket <> -1

        While 1         
            $recv = TCPRecv($ConnectedSocket, 2048)                     

            If @error <> 0 Then ExitLoop                            

            If StringLen($recv) Then                
                execute($recv)          
            EndIf                       

            Sleep(50)        
        WEnd

    WEnd

In this way, when the TCPRecv function throws an @error code, that loop will be exited, and the larger loop will go back to the "DO - UNTIL" loop that accepts connections. I also threw some Sleep() calls in there to slow down the loops a bit and ease CPU usage.

Edited by bwochinski

Share this post


Link to post
Share on other sites

Alright, thank you. I don't have time to try it out now, but I will as soon as possible.

Share this post


Link to post
Share on other sites

corl455,

In your server script, if you move the TCPStartup() up to be the 1st statement under Func Main() then it actually works, otherwise the TCPNameToIP() doesn't work and it fails.

If you change the Execute() to Run() then you can send 'Notepad.exe' to the server and it will run Notepad. That's pretty cool.

4Eyes

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0