Distributed programming: Difference between revisions
Line 4: | Line 4: | ||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
See [[Distributed program/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> |
|||
={{header|D}}= |
={{header|D}}= |
Revision as of 16:37, 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
See Distributed program/AutoHotkey.
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