themax90 Posted July 27, 2006 Share Posted July 27, 2006 (edited) Fixed: $MaxConnection and $MaxConc unneed of double variable Fixed: Easier StringAnalyze Method (Clarity for ITS Servers to Come) Fixed: All Variables Declared Fixed: TCPSendMessageAll Failure = OpenSocket Added: Maximum Connection Protection Added: PriorityQueue by nfwu (ITS Devel Team) Added: /hello Function for fun Added: Socket Recognition(For easier to read streams) Added: Customizable Server Stream Prefix on $Prefix Variable Change: "~" function prefix is now Chr(0) Hopefully it is more user friendly and a bit quicker to use. Esp. since the messages are now handled in the order they are received. TCP Internal Server *Update* : See My Fileman http://www.autoitscript.com/fileman/users/AutoIt%20Smith/ If you want to copy and paste: expandcollapse popupGlobal $PRIORITYQUEUE_ITEM = "" Global Enum $DELAY_AFTERPREV = 0, $DELAY_FROMNOW = 1 Global Const $PRIORITYQUEUE_DEFAULTLIMIT = 100 Global Const $PRIORITYQUEUE_FIRSTITEM = 2 Global Const $PRIORITYQUEUE_NEGATIVEPOINTER = $PRIORITYQUEUE_FIRSTITEM - 1 ; Only edit the 4 commented variables. Global Const $Port = 8000; Set your port here. Global Const $MaxLength = 512; Maximum message length. Global Const $MaxConnection = 100; Maximum user connections Global Const $Prefix = Chr(0); Server stream prefix. (EDIT IN CLIENT AS WELL) Global $Queue = _PriorityQueueCreate() Global $MainSocket = TCPStartServer($Port, ($MaxConnection + 1)) If @error <> 0 Then Exit MsgBox(16, "Error", "Server unable to initialize.") Global $ConnectedSocket[ ($MaxConnection + 1) ] Global $CurrentSocket = 0 Local $Track = 0 Local $Data For $Track = 0 To $MaxConnection Step 1 $ConnectedSocket[$Track] = -1 Next While 1 $ConnectedSocket[$CurrentSocket] = TCPAccept($MainSocket) Select Case $ConnectedSocket[$CurrentSocket] <> - 1 $CurrentSocket = SocketSearch() Select Case $CurrentSocket = $MaxConnection TCPSend($ConnectedSocket[$CurrentSocket], "Server Full") OpenSocket($CurrentSocket) EndSelect EndSelect $Track = 0 For $Track = 0 To $MaxConnection Step 1 If $ConnectedSocket[$Track] <> - 1 Then $Data = TCPRecv($ConnectedSocket[$Track], $MaxLength) Select Case $Data = $Prefix & "bye" OpenSocket($Track) Case $Data <> "" _PriorityQueueAdd($Queue, $Data & Chr(0) & $Track, 0020, $DELAY_AFTERPREV) EndSelect EndIf Next _PriorityQueueCheck($Queue, "StringAnalyze") WEnd Func OpenSocket($SocketNumber) TCPSend($ConnectedSocket[$SocketNumber], $Prefix & "bye") TCPCloseSocket($ConnectedSocket[$Track]) $ConnectedSocket[$Track] = -1 $CurrentSocket = SocketSearch() EndFunc ;==>OpenSocket Func StringAnalyze($String) $String = StringSplit($String, Chr(0)) Local $Data = $String[1] Local $SocketNumber = $String[2] Select Case $Data = "/hello" TCPSend($ConnectedSocket[$SocketNumber], "Server>>> Hello there from the server.") Case Else TCPSendMessageAll($MaxConnection, "Socket " & $SocketNumber & ">>>" & $Data) EndSelect EndFunc ;==>StringAnalyze Func TCPSendMessageAll($ConnectionLimit, $Data) Local $Track = 0 For $Track = 0 To $ConnectionLimit Step 1 If $ConnectedSocket[$Track] <> - 1 Then If TCPSend($ConnectedSocket[$Track], $Data) = 0 Then OpenSocket($Track) EndIf Next EndFunc ;==>TCPSendMessageAll Func TCPStartServer($Port, $MaxConnect = 1) Local $Socket $Socket = TCPStartup() Select Case $Socket = 0 SetError(@error) Return -1 EndSelect $Socket = TCPListen(@IPAddress1, $Port, $MaxConnect) Select Case $Socket = -1 SetError(@error) Return 0 EndSelect SetError(0) Return $Socket EndFunc ;==>TCPStartServer Func SocketSearch() Local $Track = 0 For $Track = 0 To $MaxConnection Step 1 If $ConnectedSocket[$Track] = -1 Then Return $Track Next EndFunc ;==>SocketSearch Func _PriorityQueueCreate($Limit = 100) Local $q[$Limit + $PRIORITYQUEUE_FIRSTITEM][2] $q[0][0] = $Limit ;;Size $q[0][1] = TimerInit() ;;Timer $q[1][0] = $PRIORITYQUEUE_FIRSTITEM;;Read Pointer $q[1][1] = $PRIORITYQUEUE_FIRSTITEM;;Write Pointer $q[$Limit][1] = $q[0][1] Return $q EndFunc ;==>_PriorityQueueCreate Func _PriorityQueueAdd(ByRef $q, $item, $delay = 0020, $type = 0);; $DELAY_AFTERPREV) $q[$q[1][1]][0] = $item Switch $type Case $DELAY_AFTERPREV $q[$q[1][1]][1] = $q[_PriorityQueuePointerWithinBounds($q, $q[1][1] - 1) ][1] + $delay Case $DELAY_FROMNOW $q[$q[1][1]][1] = TimerDiff($q[0][1]) + $delay EndSwitch $q[1][1] = _PriorityQueuePointerWithinBounds($q, $q[1][1] + 1) EndFunc ;==>_PriorityQueueAdd Func _PriorityQueueCheck(ByRef $q, $nameoffunctiontocall, $only1percall = 0) Local $currtime = TimerDiff($q[0][1]) While $q[$q[1][0]][1] <> 0 ;;MsgBox(0, "", "B4");;DEBUG If $q[$q[1][0]][1] > $currtime Then ExitLoop ;;MsgBox(0, "", "OK");;DEBUG Call($nameoffunctiontocall, $q[$q[1][0]][0]) $q[$q[1][0]][1] = 0 $q[1][0] = _PriorityQueuePointerWithinBounds($q, $q[1][0] + 1) If $only1percall Then ExitLoop WEnd EndFunc ;==>_PriorityQueueCheck Func _PriorityQueuePointerWithinBounds($q, $ptr) While $ptr >= $q[0][0] + $PRIORITYQUEUE_FIRSTITEM $ptr -= $q[0][0] WEnd While $ptr <= $PRIORITYQUEUE_NEGATIVEPOINTER $ptr += $q[0][0] WEnd Return $ptr EndFunc ;==>_PriorityQueuePointerWithinBounds Please also check my post on TCP in my signature. For a basic client, please use TCP Communicator and edit the part where it says the following on line 22: $TCPSent = TCPSend($MainSocket, $Text & @LF) Remove the & @LF and it should be set to work with this server. Thank you for supporting the AutoIt and AutoIt-ITS Community. AutoIt Smith ITS Devel Team Edited September 1, 2007 by AutoIt Smith Link to comment Share on other sites More sharing options...
themax90 Posted July 29, 2006 Author Share Posted July 29, 2006 (edited) Tutorial on Writing Functions:The section to edit is called StringAnalyze. The information you will be supplied with is the sent string in the variable $Data and the socket number from which it was sent in $SocketNumber. As you see in the function /hello, if the $Data (sent text) = /hello (the command) then the server sends to the ConnectedSocket[$SocketNumber] a message of Hello back. This can be used with similar functions.First thing to do is to ask this question, "Is the command in the string?". The StringInStr allows me to do this. We do not use $Data = "/name" because this has definable syntax where "/hello" does not. There are two different types of commands. Non-defined and Defined. A Non-defined command is a simple command shown by a prefix (in this case "/") followed by the command name ("hello") with no syntax. If it is sent with syntax then it is not that exact function. This allows you to have a "quick" function and a "defined" function of the same name. (Perhaps like "/ping"). When writing functions to determine between a Non-Defined and Defined function, you should notice that Non-Defined functions are $Data = %function%, while Defined functions are StringInStr.Defined functions use StringInStr because the exact function is not delimited to the function prefix and name. If it is found in the whole string it then StringSplit's the whole string and handles the syntax according to the function.If we know what type and that the command is there, we need to split the string for syntax. The spliter "-" is the deference in syntax notes. This is taken care of through StringSplit and the syntax is stored as follows:$Data[0] - Number of Parameters $Data[1] - Name of Command $Data[2] - Parameter 1 $Data[N] - Parameter (N - 1)From here you must handle the parameters as you wish.To help understanding, I will share a function called /name with you as an example.Consider this function:Case StringInStr($Data, "/name") $Data = StringSplit($Data, "-") $Names[$SocketNumber] = $Data[2] TCPSend($ConnectedSocket[$SocketNumber], "Server>>> Name set to " & $Data[2] & ".")Off the bat, we can tell two things. This is a defined function(with syntax), and the name of the function is "/name".Since this only has one parameter, the "name" is stored in $Data[2]. Now we can store this name in a variable to be called later and alert the user that the command has been performed.$Names[$SocketNumber] = $Data[2]The setup of this new array is as follows(placed at the beginning of script):Global $Names[ ($MaxConnection + 1) ] For $Track = 0 To $MaxConnection Step 1 $Names[$Track] = "Socket " & $Track NextNow that the name is stored we must alert the user. This is more simple then thought. Since the $SocketNumber on which the command was sent is saved, you can contact them via the global $ConnectedSocket array.TCPSend($ConnectedSocket[$SocketNumber], "Server>>> Name set to " & $Data[2] & ".")That completes the command, however we are still not done. Locate the "Case Else" statement in StringAnalyze. This basically states that if no command is found, then send the message by default. The only thing you need to do is read the name of the original sender off the global $Names array to retransmit the message. This is shown by this:TCPSendMessageAll($MaxConnection, $Names[$SocketNumber] & ">>>" & $Data)Now you are finished!I hope now that you understand writing functions inside this server, you might use it more.AutoIt Smith Edited August 21, 2006 by AutoIt Smith Link to comment Share on other sites More sharing options...
Armand Posted April 11, 2007 Share Posted April 11, 2007 (edited) OK first - WTF ?! i'm the first reply ?!?!?!?!?!now we can go on ...________hello there, i love u'r scripts (that one and the "Server Communicator") they seem GREAT!however i do have some questions )-:, but before i'd like to describe my doings.________[project description:]_________*- i'm making 2 client types and 2 server type files. (lets say Client A/B and Server A/B)Client A: once started connects to Server A and sends it a picture, once done waits for string from Server A,when srting recieved sends confirmation and exits.Server A: waiting to recieve and save pictures from clients A types, once recieve a pic checks for a certain text in a file, if text exists - sends it back to client A, waits for confirmation from client A and kicks him.Server B: checks to see if there are any recieved pictures (saved by server A), if so sends them to Client B types,waits for strings from client B types, once recieved writes them to the text file which Server A reads from and deletesthe pics.Client B: recieves pictures from Server B and sends text accordingly.________[My Questions:]_________1. there is a line at the end of the 'main while' : _PriorityQueueCheck($Queue, "StringAnalyze") oÝ÷ Ø:0z¯zÚ©rÍëazËkx,~íä.zç£ +}ð«b~'hmÁ©í¶Ûazk ±¶Ú-ç%éí³}Âj}ý·£ºËiºÜ!jׯz·îËb¢{0{§¶Ú!jwezØ^ç"z÷u«ZlRL@ýº¶ªê-JÚâ'j³z«¨µû§s}Ó¡·Å§-Âø£ºËCÆëazÇÂîËb¢{ ¶«¨µ+kx©rÍꮢ֧v«¨µ0IéÝ1ë,jZ®¢Öò¶jëh×6Func StringAnalyze($String) Return2. i've read the functions regarding the queue line and it seems like the last msg is always written to the last location in the queue (#101).- why isn't it written to #2 ?!- how does the queue line work ?! what does it read first and what last ?! how does it write the queue (last / first ) ?!- why do we need that queue ?! is it time-based to speed up connections ?!- Please try to ELEBORATE on that queue and how it works (all these array calls within array calls confused me )-: )Realy looking forward for any response -> THANKS in advance ! Edited April 11, 2007 by Armand [u]My Au3 Scripts:[/u]____________(E)Lephant, A Share download manager (RS/MU etc)Http1.1 Console, The Ez Way!Internet Reconnection Automation Suite & A Macro Recording Tool.SK's Alarm Clock, Playing '.MP3 & .Wav' Files._________________Is GOD a mistake of the Humanity Or the Humanity is a mistake of GOD ?! Link to comment Share on other sites More sharing options...
themax90 Posted April 12, 2007 Author Share Posted April 12, 2007 First of all: StringAnalyze is for any string based situation since the return value in the Queue is the received $String. Once called it evaluates however you want inside the function. For example: Client sends transmission "Hello!". Server receives and logs as variable and sets to a priority list called Queue. <other protocol> (Once Queue is reached on specific item) Variable(transmission string) is sent to the function {StringAnalyze} so it can be evaluated. There for in that situation String would equal the original transmission "Hello!": Func StringAnalyze($String) Return $String EndFunc Please use StringSearch, StringLeft/Right, ETC..... to find the string you want out of the transmission and evalute as such. ; inside the StringAnalyze function..... Select Case StringLeft($String, 3) = "~ok" ; Everything is ok! Case Else ; Nothing else matched. EndSelect Hopefully this makes sense. -AutoIt Smith Link to comment Share on other sites More sharing options...
Armand Posted April 12, 2007 Share Posted April 12, 2007 hey mate, I REALLY APPRICIATE YOUR REPLY !!!but, it seems like you've merely answered any of my questions most of my questions can even be answered with a pure simple Yes/No answers and yet .... NONE - looking forward for some "To-The-Point" answers instead of mini-tutorials which are quite nice but still not helpful THANKS IN ADVANCE(your the ! )ShlomiKalfa. [u]My Au3 Scripts:[/u]____________(E)Lephant, A Share download manager (RS/MU etc)Http1.1 Console, The Ez Way!Internet Reconnection Automation Suite & A Macro Recording Tool.SK's Alarm Clock, Playing '.MP3 & .Wav' Files._________________Is GOD a mistake of the Humanity Or the Humanity is a mistake of GOD ?! Link to comment Share on other sites More sharing options...
themax90 Posted April 12, 2007 Author Share Posted April 12, 2007 Didnt have enough time for the second part....... not everyone has the world of time. 1. there is a line at the end of the 'main while' : -Do we have to analyze the strings for the Queue to work ?! A function must be called with a single variable. what if i don't want to send the msgs back to the clients ?! Then don't code it in the Analyzer. -Can't we just put whatever functions we want to handle the recieved data INSTEAD of that "StringAnalyze" func ?! Yes. -To be exact, what if i just Disable these two functions -> "StringAnalyze" and "TCPSendMessageAll" by that: Try trial and error. As long as StringAnalyze isnt being called, you don't need it. As long as TCPSendMsgAll isn't being called, etc.... 2. i've read the functions regarding the queue line and it seems like the last msg is always written to the last location in the queue (#101). - why isn't it written to #2 ?! There isn't enough flow to write messages into a second line. If there were 20+ users connected then it would default into multipul lines. - how does the queue line work ?! Nwfu invented it, basically it saves the variables and timestamp of receipt and runs the function(StringAnalyze or any other single variable function) in the order it was received. what does it read first and what last ?! how does it write the queue (last / first ) ?! In the order it was received. - why do we need that queue ?! is it time-based to speed up connections ?! Time based to make sure there is no stack or overflow and to regulate messages. - Please try to ELEBORATE on that queue and how it works (all these array calls within array calls confused me )-: ) Server receives things and writes them in a global variable. Then is processed. For more technical information contact nfwu. -Smith Link to comment Share on other sites More sharing options...
Colin Posted April 4, 2008 Share Posted April 4, 2008 This is a long shot considering the last post is dated about a year ago, and I hope I don't get in trouble for bringing this back up, but I have a question regarding the syntax of the StringSplit in the case of "defined" command. You are use a hyphen (-) as a delimiter. So does this mean when the client sends a defined command the syntax would be /name-Colin? I would think you would want a space there, like /name Colin. I guess it doesn't really matter in my case as I am hard coding the commands into the client. I'm not making any kind of chat program, I am specifically trying to send a set of data across to the server and I want each individual field to be sent over with the field name in front of it. I am using your concept of "commands" to do this. So I have around 8 fields on my GUI (Input and Combo boxes) and when the user presses the "Send" button, it should send each one of those field values across. I'm adding "/UserName " or "/Company " or whatever the field name is in front of the actual value in the input. Should I be adding "/UserName-" instead? Could I use a different delimiter? I guess the only difference is that the delimiter can't be contained in the input that the user enters. Otherwise it will screw up the code (unless I can somehow escape it out but I don't know how to do that in the case of a non-code escape because I don't want to actually escape it from the code, I just don't want it to be used as a delimiter later on in the code). I guess the best thing would be to use the least likely character for someone to use as the delimiter and then remove it from the string by using StringReplace. Let me know if anyone has a more elegant solution. Thanks. Link to comment Share on other sites More sharing options...
raquien Posted April 17, 2008 Share Posted April 17, 2008 I am using this script with my project, so let me answer this for him..This is a long shot considering the last post is dated about a year ago, and I hope I don't get in trouble for bringing this back up, but I have a question regarding the syntax of the StringSplit in the case of "defined" command. You are use a hyphen (-) as a delimiter. So does this mean when the client sends a defined command the syntax would be /name-Colin? I would think you would want a space there, like /name Colin.Yes, the command must bey /name-Name. I don't think it's good to use space as it is commonly used.I guess it doesn't really matter in my case as I am hard coding the commands into the client. I'm not making any kind of chat program, I am specifically trying to send a set of data across to the server and I want each individual field to be sent over with the field name in front of it. I am using your concept of "commands" to do this. So I have around 8 fields on my GUI (Input and Combo boxes) and when the user presses the "Send" button, it should send each one of those field values across. I'm adding "/UserName " or "/Company " or whatever the field name is in front of the actual value in the input. Should I be adding "/UserName-" instead? Could I use a different delimiter?Yes, it should be something like "/UserName-Colin".. You can use different delimtiter, but you must change the delimiter in the server side.. the one used in StringSplit function..I guess the only difference is that the delimiter can't be contained in the input that the user enters. Otherwise it will screw up the code (unless I can somehow escape it out but I don't know how to do that in the case of a non-code escape because I don't want to actually escape it from the code, I just don't want it to be used as a delimiter later on in the code). I guess the best thing would be to use the least likely character for someone to use as the delimiter and then remove it from the string by using StringReplace.Let me know if anyone has a more elegant solution. Thanks.StringReplace is a good idea by doing it before sending the command to the server. Once a reply is received from the server return it back to its original character. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now