Distributed programming: Difference between revisions
Line 4: | Line 4: | ||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
WinSock2 library created by derRaphael. Basic code structure created by Trikster. |
WinSock2 library created by derRaphael. Basic code structure created by Trikster. Untested. If someone reading this has two computers and AutoHotkey installed on both, please test. My other computers are all in states of semi-decay. |
||
<lang autohotkey>/* |
<lang autohotkey>/* |
||
WinSock2.ahk // a rewrite by derRaphael (w) Sep, 9 2008 |
WinSock2.ahk // a rewrite by derRaphael (w) Sep, 9 2008 |
Revision as of 15:48, 9 September 2009
You are encouraged to solve this task according to the task description, using any language you may know.
Given two computers on a network, send messages between them. The protocol used may be language-specific or not, and should be suitable for general distributed programming.
AutoHotkey
WinSock2 library created by derRaphael. Basic code structure created by Trikster. Untested. If someone reading this has two computers and AutoHotkey installed on both, please test. My other computers are all in states of semi-decay. <lang autohotkey>/* WinSock2.ahk // a rewrite by derRaphael (w) Sep, 9 2008
based on the WinLIRC Script from Chris
http://www.autohotkey.com/docs/scripts/WinLIRC.htm
and on the WinLIRC Rewrite by ZedGecko
http://www.autohotkey.com/forum/viewtopic.php?t=13829
__WSA_GetHostByName - Parts based upon scripts from DarviK and Tasman. Not much left of the origin source, but it was their achievement by doing the neccessary research.
- /
- WS2 Connect - This establishes a connection to a named resource
- The parameter is to be passed in an URI
- Port manner.
- Returns the socket upon successfull connection, otherwise it
- returns -1. In the latter case more Information is in the global
- variable __WSA_ErrMsg
- Usage-Example
- Pop3_Socket
- = WS2_Connect("mail.isp.com:110")
- See the Doc for more Information.
WS2_Connect(lpszUrl) {
Global
; split our targetURI __WinINet_InternetCrackURL("info://" lpszUrl,"__WSA")
; name our port WS2_Port := __WSA_nPort ; Init the Winsock connection if ( !( __WSA_ScriptInit() ) ; Init the Scriptvariables || !( __WSA_Startup() ) ) { ; Fire up the WSA WS2_CleanUp() ; Do a premature cleanup return -1 ; and return an error indication } ; check the URI if it's valid if (RegExMatch(__WSA_lpszHostName,"[^\d.]+")) ; Must be different than IP { WS2_IPAddress := __WSA_GetHostByName(__WSA_lpszHostName) } else { ; Let's check if the IP is valid StringSplit,__WSA_tmpIPFragment, __WSA_lpszHostName,. Loop,4 If ( ( __WSA_tmpIPFragment%A_Index%<0 ) || ( __WSA_tmpIPFragment%A_Index%>255 ) || ( __WSA_tmpIPFragment0!=4 ) ) { __WSA_IPerror = 1 Break } If (__WSA_IPerror=1) __WSA_ErrMsg .= "No valid IP Supplied" else WS2_IPAddress := __WSA_lpszHostName }
; CONVERSIONS
; The htons function returns the value in TCP/IP network byte order. ; http://msdn.microsoft.com/en-us/library/ms738557(VS.85).aspx __WSA_Port := DllCall("Ws2_32\htons", "UShort", WS2_Port)
; The inet_addr function converts a string containing an IPv4 dotted-decimal ; address into a proper address for the IN_ADDR structure. ; inet_addr: http://msdn.microsoft.com/en-us/library/ms738563(VS.85).aspx ; IN_ADDR: http://msdn.microsoft.com/en-us/library/ms738571(VS.85).aspx __WSA_InetAddr := DllCall("Ws2_32\inet_addr", "Str", WS2_IPAddress)
If ( ( __WSA_Socket:=__WSA_Socket() ) && ( __WSA_Connect() ) ) return __WSA_Socket ; All went OK, return the SocketID Else { WS2_CleanUp() ; Do a premature cleanup return -1 ; and return an error indication }
}
- WS2 OnMessage - This function defines, whatever should happen when
- a Message is received on the socket.
- Expected Parameter
- Ws2_Socket => Socket returned from WS2_Connect() Call
- UDF => An UserDefinedFunction to which the received
- Data will be passed to
- Optional Parameter
- WindowMessage => A number indicating upon which WM_Message to react
- Returns -1 on error, 0 on success
WS2_AsyncSelect(Ws2_Socket,UDF,WindowMessage="") {
Global __WSA_ErrMsg If ( ( StrLen(Ws2_Socket)=0 ) || ( StrLen(UDF)=0 ) ) { res := -1 } else { If ( (StrLen(WindowMessage)=0) || (WindowMessage+0=0) ) WindowMessage := 0x5000 res := __WSA_AsyncSelect(Ws2_Socket, UDF, WindowMessage) } return res
}
WS2_SendData(WS2_Socket,DataToSend) {
Global __WSA_ErrMsg If (__WSA_send(WS2_Socket, DataToSend)=-1) { MsgBox, 16, %A_ScriptName%: Send-Error, % __WSA_ErrMsg }
}
- WS2 Cleanup - This needs to be called whenever Your Script exits
- Usually this is invoked by some OnExit, Label subroutines.
WS2_CleanUp() {
DllCall("Ws2_32\WSACleanup")
}
WS2_Disconnect(WS2_Socket) {
Global __WSA_ErrMsg if (res := __WSA_CloseSocket(WS2_Socket)) MsgBox, 16, %A_ScriptName%: CloseSocket-Error, % __WSA_ErrMsg
}
- WS2 ScriptInit - for internal use only
- Initializes neccessary variables for this Script.
__WSA_ScriptInit() {
; CONTANTS
; We're working with version 2 of Winsock Local VersionRequested := 2 ; from http://msdn.microsoft.com/en-us/library/ms742212(VS.85).aspx Local AF_INET := 2 Local SOCK_STREAM := 1 Local IPPROTO_TCP := 6 Local FD_READ := 0x1 Local FD_CLOSE := 0x20
__AI_PASSIVE := 1
__WSA_WSVersion := VersionRequested __WSA_SocketType := SOCK_STREAM __WSA_SocketProtocol := IPPROTO_TCP __WSA_SocketAF := AF_INET __WSA_lEvent := FD_READ|FD_CLOSE
__WSA_WOULDBLOCK := 10035 ; http://www.sockets.com/err_lst1.htm#WSAECONNRESET __WSA_CONNRESET := 10054 ; http://www.sockets.com/err_lst1.htm#WSAECONNRESET
return 1
}
- WS2 Startup - for internal use only
- Initializes the Winsock 2 Adapter
__WSA_Startup() {
Global WSAData, __WSA_ErrMsg, __WSA_WSVersion
; It's a good idea, to have a __WSA_ErrMsg Container, so any Error Msgs ; may be catched by the script. __WSA_ErrMsg := ""
; Generate Structure for the lpWSAData ; as stated on http://msdn.microsoft.com/en-us/library/ms742213.aspx ; More on WSADATA (structure) to be found here: ; http://msdn.microsoft.com/en-us/library/ms741563(VS.85).aspx VarSetCapacity(WSAData, 32) result := DllCall("Ws2_32\WSAStartup", "UShort", __WSA_WSVersion, "UInt", &WSAData)
if (ErrorLevel) __WSA_ErrMsg .= "Ws2_32\WSAStartup could not be called due to error " ErrorLevel "`n" . "Winsock 2.0 or higher is required.`n" if (result!=0) __WSA_ErrMsg .= "Ws2_32\WSAStartup " __WSA_GetLastError()
If (StrLen(__WSA_ErrMsg)>0) Return -1 Else Return 1
}
- WS2 Socket Descriptor - for internal use only
- Sets type and neccessary structures for a successfull connection
__WSA_Socket() {
Global __WSA_ErrMsg, __WSA_SocketProtocol, __WSA_SocketType, __WSA_SocketAF
; Supposed to return a descriptor referencing the new socket ; http://msdn.microsoft.com/en-us/library/ms742212(VS.85).aspx __WSA_Socket := DllCall("Ws2_32\socket" , "Int", __WSA_SocketAF , "Int", __WSA_SocketType , "Int", __WSA_SocketProtocol) if (socket = -1) __WSA_ErrMsg .= "Ws2_32\socket " __WSA_GetLastError()
If (StrLen(__WSA_ErrMsg)>0) Return -1 Else Return __WSA_Socket
}
- WS2 Connection call - for internal use only
- Establishes a connection to a foreign IP at the specified port
__WSA_Connect() {
Global __WSA_ErrMsg, __WSA_Port, __WSA_Socket, __WSA_InetAddr, __WSA_SocketAF
; Generate socketaddr structure for the connect() ; http://msdn.microsoft.com/en-us/library/ms740496(VS.85).aspx __WSA_SockAddrNameLen := 16 VarSetCapacity(__WSA_SockAddr, __WSA_SockAddrNameLen) NumPut(__WSA_SocketAF, __WSA_SockAddr, 0, "UShort") NumPut(__WSA_Port, __WSA_SockAddr, 2, "UShort") NumPut(__WSA_InetAddr, __WSA_SockAddr, 4)
; The connect function establishes a connection to a specified socket. ; http://msdn.microsoft.com/en-us/library/ms737625(VS.85).aspx result := DllCall("Ws2_32\connect" , "UInt", __WSA_Socket , "UInt", &__WSA_SockAddr , "Int" , __WSA_SockAddrNameLen) if (result) __WSA_ErrMsg .= "Ws2_32\connect " __WSA_GetLastError()
If (StrLen(__WSA_ErrMsg)>0) Return -1 Else Return 1
}
/*
This code based originally upon an example by DarviK http://www.autohotkey.com/forum/topic8871.html and on the modifcations by Tasman http://www.autohotkey.com/forum/viewtopic.php?t=9937
- /
- Resolves canonical domainname to IP
__WSA_GetHostByName(url) {
Global __WSA_ErrMsg ; gethostbyname returns information about a domainname into a Hostent Structure ; http://msdn.microsoft.com/en-us/library/ms738524(VS.85).aspx IP := "" if ((PtrHostent:=DllCall("Ws2_32\gethostbyname","str",url)) != 0) { Loop, 1 ; 3 is max No of retrieved addresses If (PtrTmpIP := NumGet(NumGet(PtrHostent+12)+(offset:=(A_Index-1)*4),offset)) { IP := (IP) ? IP "|" : "" Loop, 4 ; Read our IP address IP .= NumGet(PtrTmpIP+offset,(A_Index-1 ),"UChar") "." IP := SubStr(IP,1,-1) } else ; No more IPs left Break result := IP } else { __WSA_ErrMsg .= "Ws2_32\gethostbyname failed`n " result := -1 } return result
}
- Return the last Error with a lil bit o' text if neccessary
- Note
- the txt variable is set to 0 when checking for received content
__WSA_GetLastError(txt=1) {
Err := DllCall("Ws2_32\WSAGetLastError") ExtraInfo := __WSA_ErrLookUp(RegExReplace(Err,"[^\d]")) If ((InStr(ExtraInfo,"Sorry, no")) || (txt!=1)) ExtraInfo := "" Return ( txt ? "indicated Winsock error " : "") . Err . ( txt ? "`n" ExtraInfo : "")
}
- WS2 AsyncSelect - for internal use only
- Sets up an Notification Handler for Receiving Messages
- Expected Parameters
- Socket from Initialisation
- Optional
- NotificationMsg - default 0x5000
- WSA_DataReiceiver - an different Name to standard
- wm_* processor function.
- default __WSA_ReceiveData
- Returns -1 on Error, 0 on success
__WSA_AsyncSelect(__WSA_Socket, UDF, __WSA_NotificationMsg=0x5000
,__WSA_DataReceiver="__WSA_recv")
{
Global
__WSA_UDF := UDF
OnMessage(__WSA_NotificationMsg, __WSA_DataReceiver) ; The WSAAsyncSelect function requests Windows message-based notification ; of network events for a socket. ; http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx Result := DllCall("Ws2_32\WSAAsyncSelect" , "UInt", __WSA_Socket , "UInt", __WSA_GetThisScriptHandle() , "UInt", __WSA_NotificationMsg , "Int", __WSA_lEvent) if (Result) { __WSA_ErrMsg .= "Ws2_32\WSAAsyncSelect() " . __WSA_GetLastError() Result := -1 } Return Result
}
- WS2 Receive - for internal use only
- Triggers upon Notification Handler when Receiving Messages
__WSA_recv(wParam, lParam) {
Global __WSA_UDF, __WSA_ErrMsg ; __WSA_UDF containes the name of the UserDefinedFunction to call when the event ; has been triggered and text may be processed (allthough the reveived text might ; be inclomplete, especially when receiving large chunks of data, like in eMail- ; attachments or sometimes in IRC). The UDF needs to accept two parameter: socket ; and the received buffer __WSA_Socket := wParam __WSA_BufferSize = 4096 Loop { VarSetCapacity(__WSA_Buffer, __WSA_BufferSize, 0) __WSA_BufferLength := DllCall("Ws2_32\recv" , "UInt", __WSA_Socket , "Str", __WSA_Buffer , "Int", __WSA_BufferSize , "Int", 0 ) if (__WSA_BufferLength = 0) break if (__WSA_BufferLength = -1) { __WSA_Err := __WSA_GetLastError(0) ; __WSA_WOULDBLOCK (from http://www.sockets.com/) ; The socket is marked as non-blocking (non-blocking operation mode), and ; the requested operation is not complete at this time. The operation is ; underway, but as yet incomplete. if (__WSA_Err = __WSA_WOULDBLOCK ) return 1
; __WSA_CONNRESET: (from http://www.sockets.com/) ; A connection was forcibly closed by a peer. This normally results from ; a loss of the connection on the remote socket due to a timeout or a reboot. if (__WSA_Err != __WSA_CONNRESET) __WSA_ErrMsg .= "Ws2_32\recv indicated Winsock error " __WSA_Err "`n" break }
if (StrLen(__WSA_UDF)!=0) ; If set, call UserDefinedFunction and pass Buffer to it %__WSA_UDF%(__WSA_Socket,__WSA_Buffer) } return 1
}
- WSA Send - for internal use only
- Users are encouraged to use the WS2_SendData() Function
__WSA_send(__WSA_Socket, __WSA_Data) {
Global __WSA_ErrMsg
Result := DllCall("Ws2_32\send" , "UInt", __WSA_Socket , "Str", __WSA_Data , "Int", StrLen(__WSA_Data) , "Int", 0) If (Result = -1) __WSA_ErrMsg .= "Ws2_32\send " __WSA_GetLastError() Return Result
}
- Closes Open Socket - for internal use only
- Returns 0 on success
__WSA_CloseSocket(__WSA_Socket) {
Global __WSA_ErrMsg
Result := DllCall("Ws2_32\closesocket" , "UInt", __WSA_Socket) If (Result != 0) __WSA_ErrMsg .= "Ws2_32\closesocket " __WSA_GetLastError()
Return result
}
- GetThisScriptHandle - for internal use only
- Returns the handle of the executing script
__WSA_GetThisScriptHandle() {
HiddenWindowsSave := A_DetectHiddenWindows
DetectHiddenWindows On ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " DllCall("GetCurrentProcessId")) DetectHiddenWindows %HiddenWindowsSave%
Return ScriptMainWindowId
}
- Lookup Winsock ErrCode - for internal use only
- This list is form http://www.sockets.com
__WSA_ErrLookUp(sNumber) { WSA_ErrorList = (LTrim Join`n
10004 - Interrupted system call 10009 - Bad file number 10013 - Permission denied 10014 - Bad address 10022 - Invalid argument 10024 - Too many open files 10035 - Operation would block 10036 - Operation now in progress 10037 - Operation already in progress 10038 - Socket operation on non-socket 10039 - D estination address required 10040 - Message too long 10041 - Protocol wrong type for socket 10042 - Bad protocol option 10043 - Protocol not supported 10044 - Socket type not supported 10045 - Operation not supported on socket 10046 - Protocol family not supported 10047 - Address family not supported by protocol family 10048 - Address already in use 10049 - Can't assign requested address 10050 - Network is down 10051 - Network is unreachable 10052 - Net dropped connection or reset 10053 - Software caused connection abort 10054 - Connection reset by peer 10055 - No buffer space available 10056 - Socket is already connected 10057 - Socket is not connected 10058 - Can't send after socket shutdown 10059 - Too many references, can't splice 10060 - Connection timed out 10061 - Connection refused 10062 - Too many levels of symbolic links 10063 - File name too long 10064 - Host is down 10065 - No Route to Host 10066 - Directory not empty 10067 - Too many processes 10068 - Too many users 10069 - Disc Quota Exceeded 10070 - Stale NFS file handle 10091 - Network SubSystem is unavailable 10092 - WINSOCK DLL Version out of range 10093 - Successful WSASTARTUP not yet performed 10071 - Too many levels of remote in path 11001 - Host not found 11002 - Non-Authoritative Host not found 11003 - Non-Recoverable errors: FORMERR, REFUSED, NOTIMP 11004 - Valid name, no data record of requested type 11004 - No address, look for MX record
) ExNr := 0, ExErr := "Sorry, but no definition available." Loop,Parse,WSA_ErrorList,`n {
RegExMatch(A_LoopField,"(?P<Nr>\d+) - (?P<Err>.*)",Ex) if (sNumber = ExNr) break
} Return ExNr " means " ExErr "`n" }
- WinINet InternetCrackURL - for internal use only
- v 0.1 / (w) 25.07.2008 by derRaphael / zLib-Style release
- This routine was originally posted here
- http://www.autohotkey.com/forum/viewtopic.php?p=209957#209957
__WinINet_InternetCrackURL(lpszUrl,arrayName="URL") {
local hModule, offset_name_length hModule := DllCall("LoadLibrary", "Str", "WinINet.Dll")
; SetUpStructures for URL_COMPONENTS / needed for InternetCrackURL ; http://msdn.microsoft.com/en-us/library/aa385420(VS.85).aspx offset_name_length:= "4-lpszScheme-255|16-lpszHostName-1024|28-lpszUserName-1024|" . "36-lpszPassword-1024|44-lpszUrlPath-1024|52-lpszExtrainfo-1024"
VarSetCapacity(URL_COMPONENTS,60,0) ; Struc Size ; Scheme Size ; Max Port Number NumPut(60,URL_COMPONENTS,0), NumPut(255,URL_COMPONENTS,12), NumPut(0xffff,URL_COMPONENTS,24) Loop,Parse,offset_name_length,| { RegExMatch(A_LoopField,"(?P<Offset>\d+)-(?P<Name>[a-zA-Z]+)-(?P<Size>\d+)",iCU_) VarSetCapacity(%iCU_Name%,iCU_Size,0) NumPut(&%iCU_Name%,URL_COMPONENTS,iCU_Offset) NumPut(iCU_Size,URL_COMPONENTS,iCU_Offset+4) }
; Split the given URL; extract scheme, user, pass, authotity (host), port, path, and query (extrainfo) ; http://msdn.microsoft.com/en-us/library/aa384376(VS.85).aspx DllCall("WinINet\InternetCrackUrlA","Str",lpszUrl,"uInt",StrLen(lpszUrl),"uInt",0,"uInt",&URL_COMPONENTS) ; Update variables to retrieve results Loop,Parse,offset_name_length,| { RegExMatch(A_LoopField,"-(?P<Name>[a-zA-Z]+)-",iCU_) VarSetCapacity(%iCU_Name%,-1) %arrayName%_%iCU_Name% := % %iCU_Name% } %arrayName%_nPort:=NumGet(URL_COMPONENTS,24,"uInt") DllCall("FreeLibrary", "UInt", hModule) ; unload the library
}
- Persistent
- SingleInstance, force
- Include WinSock2.ahk ; derRaphaels WinSock Rewrite
SetBatchLines, -1 SetWorkingDir, %A_ScriptDir% Gui, Add, Button, gB1, Button number One! Gui, Add, Edit, vE1, Type in me! Gui, Add, Button, gB2, Press me after you're done typing! Gui, Add, DropDownList, vDDL1 gDDL1, Select something!||One|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten Gui, Add, Button, gB3, Click me!
Server := "irc.freenode.net" Port := "6667"
Channel := "#UIHjbfilgbafLIEfbAIJCICBGncaiJBHiwehFIUHEIbnjKCINJEhiUAHEJcKLACui" ; Choose something long and random - a channel sure to be deserted.
Nick := "somenick" ; Register this! You can drop it later if you want, but register it! Pass := "somepass" ; It can be any nick and any pass.
Name := "distributed program"
BotCmd := "!" OtherBotCmd := "~"
OnExit, CleanUp WS2_CleanUp() If (!Socket := WS2_Connect(Connection := Server . ":" . Port)) {
MsgBox, 16, Error!, An error occured wilist connecting to %Connection%
}
; Set OnMessage function WS2_AsyncSelect(Socket, "DataProcess") ; Send AUTH info to the server ; USER A-trivial-nickname a-domain-like-google.com some-trivial-stuff :your-real-name WS2_SendData(Socket, "USER " . Nick . " google.com AHKBOT :" . Name . "`n") ; All data send to the server must be ; followed by a newline. ; PASS A-trivial-pass WS2_SendData(Socket, "PASS " . Pass . "`n") ; NICK A-trivial-nick WS2_SendData(Socket, "NICK " . Nick . "`n") ; Join channel ; JOIN A-trivial-channel WS2_SendData(Socket, "JOIN " . Channel . "`n") Gui, Show
Return
DataProcess(Socket, Data) ; OnMessage function {
global Server,Port,Channel,Nick,Pass,Name,BotCMD StringSplit, Param, Data, %A_Space% Name := SubStr(Data, 2, InStr(Data, "!")-2) StringReplace, Command, Param5, % Chr(10),, All StringReplace, Command, Command, % Chr(13),, All If (Param1 == "PING") WS2_SendData(Socket, "PONG " . Param2 . "`n") Else If (RegExMatch(Data, ":\" . BotCMD . " ")) { If (Command == "B1" MsgBox, The other person pressed Button Number One Else If (Command == "B2E1") { MsgBox, The other person typed in Edit One then pressed Button Two Loop { If (A_Index <= 6) continue If Param%A_Index% out := out . " " . Param%A_Index% Else break } MsgBox, The other person typed:%out% } Else If (Command == "DDL1") MsgBox, The other person selected %Param7% in the drop-down-list. Else If (Command == "B3") MsgBox, The other person clicked Button Three. } return
} B1: WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B1" return B2: Gui, Submit, NoHide WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B2E1 " . E1 . " | " . B2 return DDL1: Gui, Submit, NoHide WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " DDL1 " . DDL1 return B3: WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B3" return CleanUp: GuiClose: WS2_CleanUp() ExitApp</lang>
Put the above on one computer, and run it. Then put the below on a different computer (no need for a network, just add Internet!) and run it.
<lang autohotkey>/* WinSock2.ahk // a rewrite by derRaphael (w) Sep, 9 2008
based on the WinLIRC Script from Chris
http://www.autohotkey.com/docs/scripts/WinLIRC.htm
and on the WinLIRC Rewrite by ZedGecko
http://www.autohotkey.com/forum/viewtopic.php?t=13829
__WSA_GetHostByName - Parts based upon scripts from DarviK and Tasman. Not much left of the origin source, but it was their achievement by doing the neccessary research.
- /
- WS2 Connect - This establishes a connection to a named resource
- The parameter is to be passed in an URI
- Port manner.
- Returns the socket upon successfull connection, otherwise it
- returns -1. In the latter case more Information is in the global
- variable __WSA_ErrMsg
- Usage-Example
- Pop3_Socket
- = WS2_Connect("mail.isp.com:110")
- See the Doc for more Information.
WS2_Connect(lpszUrl) {
Global
; split our targetURI __WinINet_InternetCrackURL("info://" lpszUrl,"__WSA")
; name our port WS2_Port := __WSA_nPort ; Init the Winsock connection if ( !( __WSA_ScriptInit() ) ; Init the Scriptvariables || !( __WSA_Startup() ) ) { ; Fire up the WSA WS2_CleanUp() ; Do a premature cleanup return -1 ; and return an error indication } ; check the URI if it's valid if (RegExMatch(__WSA_lpszHostName,"[^\d.]+")) ; Must be different than IP { WS2_IPAddress := __WSA_GetHostByName(__WSA_lpszHostName) } else { ; Let's check if the IP is valid StringSplit,__WSA_tmpIPFragment, __WSA_lpszHostName,. Loop,4 If ( ( __WSA_tmpIPFragment%A_Index%<0 ) || ( __WSA_tmpIPFragment%A_Index%>255 ) || ( __WSA_tmpIPFragment0!=4 ) ) { __WSA_IPerror = 1 Break } If (__WSA_IPerror=1) __WSA_ErrMsg .= "No valid IP Supplied" else WS2_IPAddress := __WSA_lpszHostName }
; CONVERSIONS
; The htons function returns the value in TCP/IP network byte order. ; http://msdn.microsoft.com/en-us/library/ms738557(VS.85).aspx __WSA_Port := DllCall("Ws2_32\htons", "UShort", WS2_Port)
; The inet_addr function converts a string containing an IPv4 dotted-decimal ; address into a proper address for the IN_ADDR structure. ; inet_addr: http://msdn.microsoft.com/en-us/library/ms738563(VS.85).aspx ; IN_ADDR: http://msdn.microsoft.com/en-us/library/ms738571(VS.85).aspx __WSA_InetAddr := DllCall("Ws2_32\inet_addr", "Str", WS2_IPAddress)
If ( ( __WSA_Socket:=__WSA_Socket() ) && ( __WSA_Connect() ) ) return __WSA_Socket ; All went OK, return the SocketID Else { WS2_CleanUp() ; Do a premature cleanup return -1 ; and return an error indication }
}
- WS2 OnMessage - This function defines, whatever should happen when
- a Message is received on the socket.
- Expected Parameter
- Ws2_Socket => Socket returned from WS2_Connect() Call
- UDF => An UserDefinedFunction to which the received
- Data will be passed to
- Optional Parameter
- WindowMessage => A number indicating upon which WM_Message to react
- Returns -1 on error, 0 on success
WS2_AsyncSelect(Ws2_Socket,UDF,WindowMessage="") {
Global __WSA_ErrMsg If ( ( StrLen(Ws2_Socket)=0 ) || ( StrLen(UDF)=0 ) ) { res := -1 } else { If ( (StrLen(WindowMessage)=0) || (WindowMessage+0=0) ) WindowMessage := 0x5000 res := __WSA_AsyncSelect(Ws2_Socket, UDF, WindowMessage) } return res
}
WS2_SendData(WS2_Socket,DataToSend) {
Global __WSA_ErrMsg If (__WSA_send(WS2_Socket, DataToSend)=-1) { MsgBox, 16, %A_ScriptName%: Send-Error, % __WSA_ErrMsg }
}
- WS2 Cleanup - This needs to be called whenever Your Script exits
- Usually this is invoked by some OnExit, Label subroutines.
WS2_CleanUp() {
DllCall("Ws2_32\WSACleanup")
}
WS2_Disconnect(WS2_Socket) {
Global __WSA_ErrMsg if (res := __WSA_CloseSocket(WS2_Socket)) MsgBox, 16, %A_ScriptName%: CloseSocket-Error, % __WSA_ErrMsg
}
- WS2 ScriptInit - for internal use only
- Initializes neccessary variables for this Script.
__WSA_ScriptInit() {
; CONTANTS
; We're working with version 2 of Winsock Local VersionRequested := 2 ; from http://msdn.microsoft.com/en-us/library/ms742212(VS.85).aspx Local AF_INET := 2 Local SOCK_STREAM := 1 Local IPPROTO_TCP := 6 Local FD_READ := 0x1 Local FD_CLOSE := 0x20
__AI_PASSIVE := 1
__WSA_WSVersion := VersionRequested __WSA_SocketType := SOCK_STREAM __WSA_SocketProtocol := IPPROTO_TCP __WSA_SocketAF := AF_INET __WSA_lEvent := FD_READ|FD_CLOSE
__WSA_WOULDBLOCK := 10035 ; http://www.sockets.com/err_lst1.htm#WSAECONNRESET __WSA_CONNRESET := 10054 ; http://www.sockets.com/err_lst1.htm#WSAECONNRESET
return 1
}
- WS2 Startup - for internal use only
- Initializes the Winsock 2 Adapter
__WSA_Startup() {
Global WSAData, __WSA_ErrMsg, __WSA_WSVersion
; It's a good idea, to have a __WSA_ErrMsg Container, so any Error Msgs ; may be catched by the script. __WSA_ErrMsg := ""
; Generate Structure for the lpWSAData ; as stated on http://msdn.microsoft.com/en-us/library/ms742213.aspx ; More on WSADATA (structure) to be found here: ; http://msdn.microsoft.com/en-us/library/ms741563(VS.85).aspx VarSetCapacity(WSAData, 32) result := DllCall("Ws2_32\WSAStartup", "UShort", __WSA_WSVersion, "UInt", &WSAData)
if (ErrorLevel) __WSA_ErrMsg .= "Ws2_32\WSAStartup could not be called due to error " ErrorLevel "`n" . "Winsock 2.0 or higher is required.`n" if (result!=0) __WSA_ErrMsg .= "Ws2_32\WSAStartup " __WSA_GetLastError()
If (StrLen(__WSA_ErrMsg)>0) Return -1 Else Return 1
}
- WS2 Socket Descriptor - for internal use only
- Sets type and neccessary structures for a successfull connection
__WSA_Socket() {
Global __WSA_ErrMsg, __WSA_SocketProtocol, __WSA_SocketType, __WSA_SocketAF
; Supposed to return a descriptor referencing the new socket ; http://msdn.microsoft.com/en-us/library/ms742212(VS.85).aspx __WSA_Socket := DllCall("Ws2_32\socket" , "Int", __WSA_SocketAF , "Int", __WSA_SocketType , "Int", __WSA_SocketProtocol) if (socket = -1) __WSA_ErrMsg .= "Ws2_32\socket " __WSA_GetLastError()
If (StrLen(__WSA_ErrMsg)>0) Return -1 Else Return __WSA_Socket
}
- WS2 Connection call - for internal use only
- Establishes a connection to a foreign IP at the specified port
__WSA_Connect() {
Global __WSA_ErrMsg, __WSA_Port, __WSA_Socket, __WSA_InetAddr, __WSA_SocketAF
; Generate socketaddr structure for the connect() ; http://msdn.microsoft.com/en-us/library/ms740496(VS.85).aspx __WSA_SockAddrNameLen := 16 VarSetCapacity(__WSA_SockAddr, __WSA_SockAddrNameLen) NumPut(__WSA_SocketAF, __WSA_SockAddr, 0, "UShort") NumPut(__WSA_Port, __WSA_SockAddr, 2, "UShort") NumPut(__WSA_InetAddr, __WSA_SockAddr, 4)
; The connect function establishes a connection to a specified socket. ; http://msdn.microsoft.com/en-us/library/ms737625(VS.85).aspx result := DllCall("Ws2_32\connect" , "UInt", __WSA_Socket , "UInt", &__WSA_SockAddr , "Int" , __WSA_SockAddrNameLen) if (result) __WSA_ErrMsg .= "Ws2_32\connect " __WSA_GetLastError()
If (StrLen(__WSA_ErrMsg)>0) Return -1 Else Return 1
}
/*
This code based originally upon an example by DarviK http://www.autohotkey.com/forum/topic8871.html and on the modifcations by Tasman http://www.autohotkey.com/forum/viewtopic.php?t=9937
- /
- Resolves canonical domainname to IP
__WSA_GetHostByName(url) {
Global __WSA_ErrMsg ; gethostbyname returns information about a domainname into a Hostent Structure ; http://msdn.microsoft.com/en-us/library/ms738524(VS.85).aspx IP := "" if ((PtrHostent:=DllCall("Ws2_32\gethostbyname","str",url)) != 0) { Loop, 1 ; 3 is max No of retrieved addresses If (PtrTmpIP := NumGet(NumGet(PtrHostent+12)+(offset:=(A_Index-1)*4),offset)) { IP := (IP) ? IP "|" : "" Loop, 4 ; Read our IP address IP .= NumGet(PtrTmpIP+offset,(A_Index-1 ),"UChar") "." IP := SubStr(IP,1,-1) } else ; No more IPs left Break result := IP } else { __WSA_ErrMsg .= "Ws2_32\gethostbyname failed`n " result := -1 } return result
}
- Return the last Error with a lil bit o' text if neccessary
- Note
- the txt variable is set to 0 when checking for received content
__WSA_GetLastError(txt=1) {
Err := DllCall("Ws2_32\WSAGetLastError") ExtraInfo := __WSA_ErrLookUp(RegExReplace(Err,"[^\d]")) If ((InStr(ExtraInfo,"Sorry, no")) || (txt!=1)) ExtraInfo := "" Return ( txt ? "indicated Winsock error " : "") . Err . ( txt ? "`n" ExtraInfo : "")
}
- WS2 AsyncSelect - for internal use only
- Sets up an Notification Handler for Receiving Messages
- Expected Parameters
- Socket from Initialisation
- Optional
- NotificationMsg - default 0x5000
- WSA_DataReiceiver - an different Name to standard
- wm_* processor function.
- default __WSA_ReceiveData
- Returns -1 on Error, 0 on success
__WSA_AsyncSelect(__WSA_Socket, UDF, __WSA_NotificationMsg=0x5000
,__WSA_DataReceiver="__WSA_recv")
{
Global
__WSA_UDF := UDF
OnMessage(__WSA_NotificationMsg, __WSA_DataReceiver) ; The WSAAsyncSelect function requests Windows message-based notification ; of network events for a socket. ; http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx Result := DllCall("Ws2_32\WSAAsyncSelect" , "UInt", __WSA_Socket , "UInt", __WSA_GetThisScriptHandle() , "UInt", __WSA_NotificationMsg , "Int", __WSA_lEvent) if (Result) { __WSA_ErrMsg .= "Ws2_32\WSAAsyncSelect() " . __WSA_GetLastError() Result := -1 } Return Result
}
- WS2 Receive - for internal use only
- Triggers upon Notification Handler when Receiving Messages
__WSA_recv(wParam, lParam) {
Global __WSA_UDF, __WSA_ErrMsg ; __WSA_UDF containes the name of the UserDefinedFunction to call when the event ; has been triggered and text may be processed (allthough the reveived text might ; be inclomplete, especially when receiving large chunks of data, like in eMail- ; attachments or sometimes in IRC). The UDF needs to accept two parameter: socket ; and the received buffer __WSA_Socket := wParam __WSA_BufferSize = 4096 Loop { VarSetCapacity(__WSA_Buffer, __WSA_BufferSize, 0) __WSA_BufferLength := DllCall("Ws2_32\recv" , "UInt", __WSA_Socket , "Str", __WSA_Buffer , "Int", __WSA_BufferSize , "Int", 0 ) if (__WSA_BufferLength = 0) break if (__WSA_BufferLength = -1) { __WSA_Err := __WSA_GetLastError(0) ; __WSA_WOULDBLOCK (from http://www.sockets.com/) ; The socket is marked as non-blocking (non-blocking operation mode), and ; the requested operation is not complete at this time. The operation is ; underway, but as yet incomplete. if (__WSA_Err = __WSA_WOULDBLOCK ) return 1
; __WSA_CONNRESET: (from http://www.sockets.com/) ; A connection was forcibly closed by a peer. This normally results from ; a loss of the connection on the remote socket due to a timeout or a reboot. if (__WSA_Err != __WSA_CONNRESET) __WSA_ErrMsg .= "Ws2_32\recv indicated Winsock error " __WSA_Err "`n" break }
if (StrLen(__WSA_UDF)!=0) ; If set, call UserDefinedFunction and pass Buffer to it %__WSA_UDF%(__WSA_Socket,__WSA_Buffer) } return 1
}
- WSA Send - for internal use only
- Users are encouraged to use the WS2_SendData() Function
__WSA_send(__WSA_Socket, __WSA_Data) {
Global __WSA_ErrMsg
Result := DllCall("Ws2_32\send" , "UInt", __WSA_Socket , "Str", __WSA_Data , "Int", StrLen(__WSA_Data) , "Int", 0) If (Result = -1) __WSA_ErrMsg .= "Ws2_32\send " __WSA_GetLastError() Return Result
}
- Closes Open Socket - for internal use only
- Returns 0 on success
__WSA_CloseSocket(__WSA_Socket) {
Global __WSA_ErrMsg
Result := DllCall("Ws2_32\closesocket" , "UInt", __WSA_Socket) If (Result != 0) __WSA_ErrMsg .= "Ws2_32\closesocket " __WSA_GetLastError()
Return result
}
- GetThisScriptHandle - for internal use only
- Returns the handle of the executing script
__WSA_GetThisScriptHandle() {
HiddenWindowsSave := A_DetectHiddenWindows
DetectHiddenWindows On ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " DllCall("GetCurrentProcessId")) DetectHiddenWindows %HiddenWindowsSave%
Return ScriptMainWindowId
}
- Lookup Winsock ErrCode - for internal use only
- This list is form http://www.sockets.com
__WSA_ErrLookUp(sNumber) { WSA_ErrorList = (LTrim Join`n
10004 - Interrupted system call 10009 - Bad file number 10013 - Permission denied 10014 - Bad address 10022 - Invalid argument 10024 - Too many open files 10035 - Operation would block 10036 - Operation now in progress 10037 - Operation already in progress 10038 - Socket operation on non-socket 10039 - D estination address required 10040 - Message too long 10041 - Protocol wrong type for socket 10042 - Bad protocol option 10043 - Protocol not supported 10044 - Socket type not supported 10045 - Operation not supported on socket 10046 - Protocol family not supported 10047 - Address family not supported by protocol family 10048 - Address already in use 10049 - Can't assign requested address 10050 - Network is down 10051 - Network is unreachable 10052 - Net dropped connection or reset 10053 - Software caused connection abort 10054 - Connection reset by peer 10055 - No buffer space available 10056 - Socket is already connected 10057 - Socket is not connected 10058 - Can't send after socket shutdown 10059 - Too many references, can't splice 10060 - Connection timed out 10061 - Connection refused 10062 - Too many levels of symbolic links 10063 - File name too long 10064 - Host is down 10065 - No Route to Host 10066 - Directory not empty 10067 - Too many processes 10068 - Too many users 10069 - Disc Quota Exceeded 10070 - Stale NFS file handle 10091 - Network SubSystem is unavailable 10092 - WINSOCK DLL Version out of range 10093 - Successful WSASTARTUP not yet performed 10071 - Too many levels of remote in path 11001 - Host not found 11002 - Non-Authoritative Host not found 11003 - Non-Recoverable errors: FORMERR, REFUSED, NOTIMP 11004 - Valid name, no data record of requested type 11004 - No address, look for MX record
) ExNr := 0, ExErr := "Sorry, but no definition available." Loop,Parse,WSA_ErrorList,`n {
RegExMatch(A_LoopField,"(?P<Nr>\d+) - (?P<Err>.*)",Ex) if (sNumber = ExNr) break
} Return ExNr " means " ExErr "`n" }
- WinINet InternetCrackURL - for internal use only
- v 0.1 / (w) 25.07.2008 by derRaphael / zLib-Style release
- This routine was originally posted here
- http://www.autohotkey.com/forum/viewtopic.php?p=209957#209957
__WinINet_InternetCrackURL(lpszUrl,arrayName="URL") {
local hModule, offset_name_length hModule := DllCall("LoadLibrary", "Str", "WinINet.Dll")
; SetUpStructures for URL_COMPONENTS / needed for InternetCrackURL ; http://msdn.microsoft.com/en-us/library/aa385420(VS.85).aspx offset_name_length:= "4-lpszScheme-255|16-lpszHostName-1024|28-lpszUserName-1024|" . "36-lpszPassword-1024|44-lpszUrlPath-1024|52-lpszExtrainfo-1024"
VarSetCapacity(URL_COMPONENTS,60,0) ; Struc Size ; Scheme Size ; Max Port Number NumPut(60,URL_COMPONENTS,0), NumPut(255,URL_COMPONENTS,12), NumPut(0xffff,URL_COMPONENTS,24) Loop,Parse,offset_name_length,| { RegExMatch(A_LoopField,"(?P<Offset>\d+)-(?P<Name>[a-zA-Z]+)-(?P<Size>\d+)",iCU_) VarSetCapacity(%iCU_Name%,iCU_Size,0) NumPut(&%iCU_Name%,URL_COMPONENTS,iCU_Offset) NumPut(iCU_Size,URL_COMPONENTS,iCU_Offset+4) }
; Split the given URL; extract scheme, user, pass, authotity (host), port, path, and query (extrainfo) ; http://msdn.microsoft.com/en-us/library/aa384376(VS.85).aspx DllCall("WinINet\InternetCrackUrlA","Str",lpszUrl,"uInt",StrLen(lpszUrl),"uInt",0,"uInt",&URL_COMPONENTS) ; Update variables to retrieve results Loop,Parse,offset_name_length,| { RegExMatch(A_LoopField,"-(?P<Name>[a-zA-Z]+)-",iCU_) VarSetCapacity(%iCU_Name%,-1) %arrayName%_%iCU_Name% := % %iCU_Name% } %arrayName%_nPort:=NumGet(URL_COMPONENTS,24,"uInt") DllCall("FreeLibrary", "UInt", hModule) ; unload the library
}
- Persistent
- SingleInstance, force
- Include WinSock2.ahk ; derRaphaels WinSock Rewrite
SetBatchLines, -1 SetWorkingDir, %A_ScriptDir% Gui, Add, Button, gB1, Button number One! Gui, Add, Edit, vE1, Type in me! Gui, Add, Button, gB2, Press me after you're done typing! Gui, Add, DropDownList, vDDL1 gDDL1, Select something!||One|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten Gui, Add, Button, gB3, Click me!
Server := "irc.freenode.net" Port := "6667"
Channel := "#UIHjbfilgbafLIEfbAIJCICBGncaiJBHiwehFIUHEIbnjKCINJEhiUAHEJcKLACui" ; Choose something long and random - a channel sure to be deserted.
Nick := "someothernick" ; Register this! You can drop it later if you want, but register it! Pass := "someotherpass" ; It can be any nick and any pass.
Name := "distributed program"
BotCmd := "~" OtherBotCmd := "!"
OnExit, CleanUp WS2_CleanUp() If (!Socket := WS2_Connect(Connection := Server . ":" . Port)) {
MsgBox, 16, Error!, An error occured wilist connecting to %Connection%
}
; Set OnMessage function WS2_AsyncSelect(Socket, "DataProcess") ; Send AUTH info to the server ; USER A-trivial-nickname a-domain-like-google.com some-trivial-stuff :your-real-name WS2_SendData(Socket, "USER " . Nick . " google.com AHKBOT :" . Name . "`n") ; All data send to the server must be ; followed by a newline. ; PASS A-trivial-pass WS2_SendData(Socket, "PASS " . Pass . "`n") ; NICK A-trivial-nick WS2_SendData(Socket, "NICK " . Nick . "`n") ; Join channel ; JOIN A-trivial-channel WS2_SendData(Socket, "JOIN " . Channel . "`n") Gui, Show
Return
DataProcess(Socket, Data) ; OnMessage function {
global Server,Port,Channel,Nick,Pass,Name,BotCMD StringSplit, Param, Data, %A_Space% Name := SubStr(Data, 2, InStr(Data, "!")-2) StringReplace, Command, Param5, % Chr(10),, All StringReplace, Command, Command, % Chr(13),, All If (Param1 == "PING") WS2_SendData(Socket, "PONG " . Param2 . "`n") Else If (RegExMatch(Data, ":\" . BotCMD . " ")) { If (Command == "B1" MsgBox, The other person pressed Button Number One Else If (Command == "B2E1") { MsgBox, The other person typed in Edit One then pressed Button Two Loop { If (A_Index <= 6) continue If Param%A_Index% out := out . " " . Param%A_Index% Else break } MsgBox, The other person typed:%out% } Else If (Command == "DDL1") MsgBox, The other person selected %Param7% in the drop-down-list. Else If (Command == "B3") MsgBox, The other person clicked Button Three. } return
} B1: WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B1" return B2: Gui, Submit, NoHide WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B2E1 " . E1 . " | " . B2 return DDL1: Gui, Submit, NoHide WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " DDL1 " . DDL1 return B3: WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B3" return CleanUp: GuiClose: WS2_CleanUp() ExitApp</lang>
D
Socket
Server
<lang d>module distributedserver ; import tango.net.ServerSocket, tango.text.convert.Integer,
tango.text.Util, tango.io.Stdout ;
void main() {
auto Ip = new InternetAddress("localhost", 12345) ; auto server = new ServerSocket(Ip) ; auto socket = server.accept ; auto buffer = new char[socket.bufferSize] ;
bool quit = false ; while(!quit) { bool error = false ; try { auto len = socket.input.read(buffer) ; auto cmd = (len > 0) ? delimit(buffer[0..len], " ") : [""] ; Stdout(cmd).newline.flush ; switch (cmd[0]) { case "square": socket.output.write(toString(toInt(cmd[1]) * toInt(cmd[1]))) ; break ; case"add": socket.output.write(toString(toInt(cmd[1]) + toInt(cmd[2]))) ; break ; case "quit": socket.output.write("Server Shut down") ; quit = true ; break ; default: error = true ; } } catch (Exception e) error = true ; if(error) socket.output.write("<Error>") ; if(socket) socket.close ; if(!quit) socket = server.accept ; }
if(socket) socket.close ;
}</lang>
Client
<lang d>module distributedclient ; import tango.net.SocketConduit, tango.net.InternetAddress,
tango.text.Util, tango.io.Stdout ;
void main(char[][] args) {
if(args.length> 1) { try { auto Ip = new InternetAddress("localhost", 12345) ; auto socket = new SocketConduit ; socket.connect(Ip) ; auto buffer = new char[socket.bufferSize] ; socket.output.write(join(args[1..$]," ")) ; auto len = socket.input.read(buffer) ; if(len > 0) Stdout(buffer[0..len]).newline ; if(socket) socket.close ; } catch(Exception e) Stdout(e.msg).newline ; } else Stdout("usage: supply argument as,\n\tquit\n" "\tsquare <number>\n\tadd <number> <number>").newline ;
}</lang>
E
Protocol: Pluribus
This service cannot be used except by clients which know the URL designating it, messages are encrypted, and the client authenticates the server. However, it is vulnerable to denial-of-service by any client knowing the URL.
Server
(The protocol is symmetric; this program is the server only in that it is the one which is started first and exports an object.)
<lang e> def storage := [].diverge()
def logService { to log(line :String) { storage.push([timer.now(), line]) } to search(substring :String) { var matches := [] for [time, line] ? (line.startOf(substring) != -1) in storage { matches with= [time, line] } return matches } } introducer.onTheAir() def sturdyRef := makeSturdyRef.temp(logService) println(<captp>.sturdyToURI(sturdyRef)) interp.blockAtTop()</lang>
This will print the URL of the service and run it until aborted.
Client
The URL provided by the server is given as the argument to this program.
<lang e> def [uri] := interp.getArgs()
introducer.onTheAir() def sturdyRef := <captp>.sturdyFromURI(uri) def logService := sturdyRef.getRcvr() logService <- log("foot") logService <- log("shoe") println("Searching...") when (def result := logService <- search("foo")) -> { for [time, line] in result { println(`At $time: $line`) } }</lang>
Erlang
The protocol is erlang's own
Server
srv.erl
<lang erlang> -module(srv).
-export([start/0, wait/0]). start() -> net_kernel:start([srv,shortnames]), erlang:set_cookie(node(), rosetta), Pid = spawn(srv,wait,[]), register(srv,Pid), io:fwrite("~p ready~n",[node(Pid)]), ok. wait() -> receive {echo, Pid, Any} -> io:fwrite("-> ~p from ~p~n", [Any, node(Pid)]), Pid ! {hello, Any}, wait(); Any -> io:fwrite("Error ~p~n", [Any]) end.</lang>
Client
client.erl
<lang erlang> -module(client).
-export([start/0, wait/0]). start() -> net_kernel:start([client,shortnames]), erlang:set_cookie(node(), rosetta), {ok,Srv} = init:get_argument(server), io:fwrite("conencting to ~p~n", [Srv]), {srv, list_to_atom(Srv)} ! {echo,self(), hi}, wait(), ok. wait() -> receive {hello, Any} -> io:fwrite("Received ~p~n", [Any]); Any -> io:fwrite("Error ~p~n", [Any]) end.</lang>
running it (*comes later)
|erlc srv.erl |erl -run srv start -noshell srv@agneyam ready *-> hi from client@agneyam
|erlc client.erl |erl -run client start -run init stop -noshell -server srv@agneyam conencting to "srv@agneyam" Received hi
Objective-C
Distributed Objects are natural to Objective-C, and OpenStep and derivated framework offers an easy way of using remote objects as if it were local. The client must only know the protocol the remote object support. For the rest, calling a remote object's method or local object's method is transparent.
Server
The server vending the object with the name DistributedAction
ActionObjectProtocol.h <lang objc>#import <Foundation/Foundation.h> // our protocol allows "sending" "strings", but we can implement // everything we could for a "local" object @protocol ActionObjectProtocol - (NSString *)sendMessage: (NSString *)msg; @end</lang>
ActionObject.h <lang objc>#import <Foundation/Foundation.h>
- import "ActionObjectProtocol.h"
@interface ActionObject : NSObject <ActionObjectProtocol>
// we do not have much for this example!
@end</lang>
ActionObject.m <lang objc>#import <Foundation/Foundation.h>
- import "ActionObject.h"
@implementation ActionObject -(NSString *)sendMessage: (NSString *)msg {
NSLog(@"client sending message %@", msg); return @"server answers ...";
} @end</lang>
server.m <lang objc>#import <Foundation/Foundation.h>
- import "ActionObject.h"
int main (void) {
NSAutoreleasePool *pool; ActionObject *action; NSConnection *connect; NSSocketPort *port; pool = [[NSAutoreleasePool alloc] init]; action = [[ActionObject alloc] init];
port = (NSSocketPort *)[NSSocketPort port]; // initWithTCPPort: 1234 and other methods are not supported yet // by GNUstep connect = [NSConnection
connectionWithReceivePort: port sendPort: port]; // or sendPort: nil
[connect setRootObject: action];
/* "vend" the object ActionObject as DistributedAction; on GNUstep the Name Server that allows the resolution of the registered name is bound to port 538 */ if ([connect registerName:@"DistributedAction"
withNameServer: [NSSocketPortNameServer sharedInstance] ] == NO)
{ NSLog(@"can't register the server DistributedAction"); exit(EXIT_FAILURE); } NSLog(@"waiting for messages...");
[[NSRunLoop currentRunLoop] run];
[pool release]; return 0;
}</lang>
Client
client.m <lang objc>#import <Foundation/Foundation.h>
- import "ActionObjectProtocol.h"
int main(void) {
NSAutoreleasePool *pool; NSArray *args; id <ActionObjectProtocol> action; NSString *msg, *backmsg;
pool = [[NSAutoreleasePool alloc] init];
action = (id <ActionObjectProtocol>) [NSConnection rootProxyForConnectionWithRegisteredName: @"DistributedAction" host: @"localhost" usingNameServer: [NSSocketPortNameServer sharedInstance] ];
if (action == nil) { NSLog(@"can't connect to the server"); exit(EXIT_FAILURE); } args = [[NSProcessInfo processInfo] arguments];
if ([args count] == 1) { NSLog(@"specify a message"); exit(EXIT_FAILURE); } msg = [args objectAtIndex: 1];
// "send" (call the selector "sendMessage:" of the (remote) object // action) the first argument's text as msg, store the message "sent // back" and then show it in the log backmsg = [action sendMessage: msg]; NSLog(backmsg);
[pool release]; return 0;
}</lang>
OCaml
Minimalistic distributed logger with synchronous channels using the join calculus on top of OCaml.
Server
<lang ocaml> open Printf
let create_logger () = def log(text) & logs(l) = printf "Logged: %s\n%!" text; logs((text, Unix.gettimeofday ())::l) & reply to log or search(text) & logs(l) = logs(l) & reply List.filter (fun (line, _) -> line = text) l to search in spawn logs([]); (log, search) def wait() & finished() = reply to wait let register name service = Join.Ns.register Join.Ns.here name service let () = let log, search = create_logger () in register "log" log; register "search" search; Join.Site.listen (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345)); wait ()</lang>
Client
<lang ocaml> open Printf
let ns_there = Join.Ns.there (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345)) let lookup name = Join.Ns.lookup ns_there name let log : string -> unit = lookup "log" let search : string -> (string * float) list = lookup "search" let find txt = printf "Looking for %s...\n" txt; List.iter (fun (line, time) -> printf "Found: '%s' at t = %f\n%!" (String.escaped line) time) (search txt) let () = log "bar"; find "foo"; log "foo"; log "shoe"; find "foo"</lang>
Python
XML-RPC
Protocol: XML-RPC
Server
<lang python>
- !/usr/bin/env python
- -*- coding: utf-8 -*-
import SimpleXMLRPCServer
class MyHandlerInstance:
def echo(self, data): Method for returning data got from client return 'Server responded: %s' % data
def div(self, num1, num2): Method for divide 2 numbers return num1/num2
def foo_function():
A function (not an instance method) return True
HOST = "localhost" PORT = 8000
server = SimpleXMLRPCServer.SimpleXMLRPCServer((HOST, PORT))
- register built-in system.* functions.
server.register_introspection_functions()
- register our instance
server.register_instance(MyHandlerInstance())
- register our function as well
server.register_function(foo_function)
try:
# serve forever server.serve_forever()
except KeyboardInterrupt:
print 'Exiting...' server.server_close()
</lang>
Client
<lang python>
- !/usr/bin/env python
- -*- coding: utf-8 -*-
import xmlrpclib
HOST = "localhost" PORT = 8000
rpc = xmlrpclib.ServerProxy("http://%s:%d" % (HOST, PORT))
- print what functions does server support
print 'Server supports these functions:', print ' '.join(rpc.system.listMethods())
- echo something
rpc.echo("We sent this data to server")
- div numbers
print 'Server says: 8 / 4 is: %d' % rpc.div(8, 4)
- control if foo_function returns True
if rpc.foo_function():
print 'Server says: foo_function returned True'
</lang>
HTTP
Protocol: HTTP
Server
<lang python>
- !/usr/bin/python
- -*- coding: utf-8 -*-
import BaseHTTPServer
HOST = "localhost" PORT = 8000
- we just want to write own class, we replace do_GET method. This could be extended, I just added basics
- see; http://docs.python.org/lib/module-BaseHTTPServer.html
class MyHTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self): # send 200 (OK) message self.send_response(200) # send header self.send_header("Content-type", "text/html") self.end_headers()
# send context self.wfile.write("<html><head><title>Our Web Title</title></head>")
self.wfile.write("<body>
This is our body. You wanted to visit %s page
</body>" % self.path)
self.wfile.write("</html>")
if __name__ == '__main__':
server = BaseHTTPServer.HTTPServer((HOST, PORT), MyHTTPHandler) try: server.serve_forever() except KeyboardInterrupt: print 'Exiting...' server.server_close()
</lang>
Client
<lang python>
- !/usr/bin/python
- -*- coding: utf-8 -*-
import httplib
HOST = "localhost" PORT = 8000
conn = httplib.HTTPConnection(HOST, PORT) conn.request("GET", "/somefile")
response = conn.getresponse() print 'Server Status: %d' % response.status
print 'Server Message: %s' % response.read() </lang>
Socket, Plain Text
Protocol: Plain Text
Server
<lang python>
- !/usr/bin/python
- -*- coding: utf-8 -*-
import SocketServer
HOST = "localhost" PORT = 8000
- our instance that will upper whatever it gets and send back to client
class UpperCaseHandler(SocketServer.StreamRequestHandler):
def handle(self): print '%s connected' % self.client_address[0] # get what client sends get = self.rfile.readline() # write back to client self.wfile.write(get.upper())
if __name__ == '__main__':
tcpserver = SocketServer.TCPServer((HOST, PORT), UpperCaseHandler) try: tcpserver.serve_forever() except KeyboardInterrupt: print 'Exiting...' tcpserver.server_close()
</lang>
Client
<lang python>
- !/usr/bin/python
- -*- coding: utf-8 -*-
import socket
HOST = "localhost" PORT = 8000
DATA = "my name is eren"
- connect to server and send data
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) sock.send("%s\n" % DATA)
- get
response = sock.recv(256) sock.close()
print "We sent: %s" % DATA print 'Server responded: %s' % response </lang>
Pyro
Note: You should install Pyro (http://pyro.sourceforge.net) first and run pyro-ns binary to run code below.
Server
<lang python>
- !/usr/bin/python
- -*- coding: utf-8 -*-
import Pyro.core import Pyro.naming
- create instance that will return upper case
class StringInstance(Pyro.core.ObjBase):
def makeUpper(self, data): return data.upper()
class MathInstance(Pyro.core.ObjBase):
def div(self, num1, num2): return num1/num2
if __name__ == '__main__':
server = Pyro.core.Daemon() name_server = Pyro.naming.NameServerLocator().getNS() server.useNameServer(name_server) server.connect(StringInstance(), 'string') server.connect(MathInstance(), 'math') try: server.requestLoop() except KeyboardInterrupt: print 'Exiting...' server.shutdown()
</lang>
Client
<lang python>
- !/usr/bin/python
- -*- coding: utf-8 -*-
import Pyro.core
DATA = "my name is eren" NUM1 = 10 NUM2 = 5
string = Pyro.core.getProxyForURI("PYRONAME://string") math = Pyro.core.getProxyForURI("PYRONAME://math")
print 'We sent: %s' % DATA print 'Server responded: %s\n' % string.makeUpper(DATA)
print 'We sent two numbers to divide: %d and %d' % (NUM1, NUM2) print 'Server responded the result: %s' % math.div(NUM1, NUM2) </lang>
Spread
Note: You should install Spread (http://www.spread.org) and its python bindings (http://www.python.org/other/spread/)
Server
You don't need any code for server. You should start "spread" daemon by typing "spread -c /etc/spread.conf -n localhost". If you want more configuration, look at /etc/spread.conf.
After starting daemon, if you want to make sure that it is running, enter spuser -s 4803 command where 4803 is your port set in spread.conf, you will see prompt, type j user, you should see something like this message: Received REGULAR membership for group test with 3 members, where I am member 2
Client (Listener)
<lang python>
- !/usr/bin/python
- -*- coding: utf-8 -*-
import spread
PORT = '4803'
- connect spread daemon
conn = spread.connect(PORT)
- join the room
conn.join('test')
print 'Waiting for messages... If you want to stop this script, please stop spread daemon' while True:
recv = conn.receive() if hasattr(recv, 'sender') and hasattr(recv, 'message'): print 'Sender: %s' % recv.sender print 'Message: %s' % recv.message
</lang>
Client (Sender)
<lang python>
- !/usr/bin/python
- -*- coding: utf-8 -*-
import spread
PORT = '4803'
conn = spread.connect(PORT) conn.join('test')
conn.multicast(spread.RELIABLE_MESS, 'test', 'hello, this is message sent from python') conn.disconnect() </lang>
Ruby
Uses
The "druby:" protocol uses TCP/IP sockets for communication.
Server <lang ruby> require 'drb/drb'
# The URI for the server to connect to URI="druby://localhost:8787"
class TimeServer
def get_current_time return Time.now end
end
# The object that handles requests on the server FRONT_OBJECT = TimeServer.new
$SAFE = 1 # disable eval() and friends
DRb.start_service(URI, FRONT_OBJECT) # Wait for the drb server thread to finish before exiting. DRb.thread.join</lang>
Client <lang ruby> require 'drb/drb'
# The URI to connect to SERVER_URI = "druby://localhost:8787"
# Start a local DRbServer to handle callbacks. # # Not necessary for this small example, but will be required # as soon as we pass a non-marshallable object as an argument # to a dRuby call. DRb.start_service
timeserver = DRbObject.new_with_uri(SERVER_URI) puts timeserver.get_current_time</lang>
Tcl
A rudimentary IRC Server <lang tcl>proc main {} {
global connections set connections [dict create] socket -server handleConnection 12345 vwait dummyVar ;# enter the event loop
}
proc handleConnection {channel clientaddr clientport} {
global connections dict set connections $channel address "$clientaddr:$clientport" fconfigure $channel -buffering line fileevent $channel readable [list handleMessage $channel]
}
proc handleMessage {channel} {
global connections if {[gets $channel line] == -1} { disconnect $channel } else { if {[string index [string trimleft $line] 0] eq "/"} { set words [lassign [split [string trim $line]] command] handleCommand $command $words $channel } else { echo $line $channel } }
}
proc disconnect {channel} {
global connections dict unset connections $channel fileevent $channel readable "" close $channel
}
proc handleCommand {command words channel} {
global connections switch -exact -- [string tolower $command] { /nick { dict set connections $channel nick [lindex $words 0] } /quit { echo bye $channel disconnect $channel } default { puts $channel "\"$command\" not implemented" } }
}
proc echo {message senderchannel} {
global connections foreach channel [dict keys $connections] { if {$channel ne $senderchannel} { set time [clock format [clock seconds] -format "%T"] set nick [dict get $connections $channel nick] puts $channel [format "\[%s\] %s: %s" $time $nick $message] } }
}
main</lang> Client <lang tcl>proc main {} {
global argv argc if {$argc != 2} { error "usage: [info script] serveraddress serverport" } connect {*}$argv vwait dummyVar
}
proc connect {addr port} {
global sock set sock [socket $addr $port] fconfigure $sock -buffering line fileevent $sock readable getFromServer fileevent stdin readable sendToServer
}
proc getFromServer {} {
global sock if {[gets $sock line] == -1} { puts "disconnected..." exit } else { puts $line }
}
proc sendToServer {} {
global sock set msg [string trim [gets stdin]] if {[string length $msg] > 0} { puts $sock $msg }
}
main</lang>
UnixPipes
Uses netcat
server
(echo 1; echo 2; echo 3) | nc -l 1024
client
nc 192.168.0.1 1024 | wc -l