@TheArkive
A blocking implementation is easier I guess?
Socket Class - 2022/09/07 - beta.8
Re: Socket Class - 2022/09/07 - beta.8
@antenne
Yes, but less convenient when trying to handle connection issues. Depending on how you code, your script can freeze until the connection finally times out, or connects.
ASYNC is better for a more robust application, but also more complex.
Yes, but less convenient when trying to handle connection issues. Depending on how you code, your script can freeze until the connection finally times out, or connects.
ASYNC is better for a more robust application, but also more complex.
« AHK Portable Installer » | « CallTipsForAll » | « TheArkive AHK v1 Scripts » | « TheArkive AHK v2 Scrpts » | « TheArkive on GitHub »
Re: Socket Class - 2022/09/07 - beta.8
@TheArkive
I think this won't be a issue, I'm only sending locally.
I think this won't be a issue, I'm only sending locally.
Re: Socket Class - 2022/09/07 - beta.8
@TheArkive
Sorry for bothering you again. But I seem to be to dumb to send a UDP String.
Could you please write an example to send an UDP String to localhost?
Thank you
Sorry for bothering you again. But I seem to be to dumb to send a UDP String.
Could you please write an example to send an UDP String to localhost?
Thank you
Re: Socket Class - 2022/09/07 - beta.8
My apologies. I meant to get to this sooner.
The following code will perform a udp example:
Sadly this example isn't as simple as it should be. It deviates a bit too much from the win32 docs. I'll probably revert some of this stuff in the future to better mirror the original MS docs.
I tried to simplify usage, but I don't think i achieved that.
EDIT:. paste this in the example file. Run script, and press F7, then F8. This is still an async example, not blocking. I'll work on that next.
The main change to use udp is this:
The following code will perform a udp example:
Code: Select all
F8::test_server_udp()
F9::test_client_udp()
test_server_udp() { ; server - uses async to accept sockets
sock := winsock("server",cb,"IPV4","UDP","DGram")
sock.Bind("0.0.0.0",27015) ; "0.0.0.0",27015
sock.Listen()
print_gui("Server listening...`r`n`r`n")
}
test_client_udp() { ; client
sock := winsock("client",cb,"IPV4","UDP","DGram")
sock.Connect("127.0.0.1",27015) ; 127.0.0.1",27015 ; www.google.com",80
print_gui("Client connecting...`r`n`r`n")
}
Sadly this example isn't as simple as it should be. It deviates a bit too much from the win32 docs. I'll probably revert some of this stuff in the future to better mirror the original MS docs.
I tried to simplify usage, but I don't think i achieved that.
EDIT:. paste this in the example file. Run script, and press F7, then F8. This is still an async example, not blocking. I'll work on that next.
The main change to use udp is this:
Code: Select all
sock := winsock("server",cb,"IPV4","UDP","DGram")
« AHK Portable Installer » | « CallTipsForAll » | « TheArkive AHK v1 Scripts » | « TheArkive AHK v2 Scrpts » | « TheArkive on GitHub »
Re: Socket Class - 2022/09/07 - beta.8
Thank you very much for Posting the example.
I managed to build my own minimal example.
Unfortunately it doesn't really work reliably. It only sends the String when there is this MsgBox and then it will be sent twice.
What am I doing wrong?
I managed to build my own minimal example.
Code: Select all
#Include _socket.ahk
sock := winsock("client",cb,"IPV4","UDP","DGram")
sock.Connect("127.0.0.1",33333)
MsgBox
cb(sock, event, err) {
get_req := "Test"
strbuf := Buffer(StrLen(get_req)+1,0)
StrPut(get_req,strbuf,"UTF-8")
sock.Send(strbuf)
}
What am I doing wrong?
Re: Socket Class - 2022/09/07 - beta.8
Read up on the async events. At a minimum, if you are only sending, you will have 2 events. See the original example for event handling.
Read up here: WSAAsyncSelect
- FD_CONNECT
On return from connect command.
Err code will indicate success or reason for fail.
- FD_WRITE
Socket is ready to write, now is the time to use send cmd
I'll clean up the example when I have more time.
As for "needing the MsgBox", that makes no sense. My example only uses msgbox to show events.
Check err codes in callback to see what is happening.
Read up here: WSAAsyncSelect
- FD_CONNECT
On return from connect command.
Err code will indicate success or reason for fail.
- FD_WRITE
Socket is ready to write, now is the time to use send cmd
I'll clean up the example when I have more time.
As for "needing the MsgBox", that makes no sense. My example only uses msgbox to show events.
Check err codes in callback to see what is happening.
« AHK Portable Installer » | « CallTipsForAll » | « TheArkive AHK v1 Scripts » | « TheArkive AHK v2 Scrpts » | « TheArkive on GitHub »
Re: Socket Class - 2022/09/07 - beta.8
You probably "need" the msgbox because of timing issues. Use the events properly and check err codes. That should fix the root of this issue.
« AHK Portable Installer » | « CallTipsForAll » | « TheArkive AHK v1 Scripts » | « TheArkive AHK v2 Scrpts » | « TheArkive on GitHub »
Re: Socket Class - 2022/09/07 - beta.8
Thank you for alle your time and effort!
I will try to dig deeper into the topic.
I will try to dig deeper into the topic.
Re: Socket Class - 2022/09/07 - beta.8
Basic http server, I use it to call ahk running in another computer (VM actually). Thanks for the winsock class.
Code: Select all
#include <_socket>
Persistent(true)
class HTTPRequest {
method := ''
path := ''
queries := Map()
headers := Map()
static URIDecode(value) {
static _UrlUnescape := DllCall(
'kernel32.dll\GetProcAddress',
'Ptr', DllCall('kernel32.dll\GetModuleHandle', 'Str', 'shlwapi.dll', 'Ptr'),
'AStr', 'UrlUnescapeW',
'Ptr'
)
return DllCall(
_UrlUnescape,
'Str', value,
'Ptr', 0,
'UInt', 0,
'UInt', 0x00140000,
'UInt'
) ? '' : value
}
__New(request) {
loop parse request, '`n', '`r' {
if !A_LoopField
break
if !this.method {
arr := StrSplit(A_LoopField, ' ')
this.method := arr[1]
if pos := InStr(arr[2], '?') {
this.path := SubStr(arr[2], 1, pos - 1)
loop parse SubStr(arr[2], pos + 1), '&' {
if pos := InStr(A_LoopField, '=') {
param := HTTPRequest.URIDecode(SubStr(A_LoopField, 1, pos - 1))
value := HTTPRequest.URIDecode(SubStr(A_LoopField, pos + 1))
this.queries[param] := value
} else {
param := HTTPRequest.URIDecode(A_LoopField)
this.queries[param] := ''
}
}
} else {
this.path := arr[2]
}
} else {
arr := StrSplit(A_LoopField, ':', ' ', 2)
this.headers[arr[1]] := arr[2]
}
}
}
}
class HTTPResponse {
static STATUS_CODES := Map(
200, 'OK',
404, 'Not Found'
)
__New(sock) {
this.sock := sock
}
Send(status, headers := Map(), content := '') {
if !IsObject(headers) && !content {
content := headers
headers := Map()
}
NL := '`r`n'
response := 'HTTP/1.1 ' status ' ' HTTPResponse.STATUS_CODES[status] NL
if !headers.Has('Content-Type') {
headers['Content-Type'] := 'text/plain'
}
if headers {
for key, value in headers {
response .= key ': ' value NL
}
}
response .= 'Content-Length: ' (StrPut(content, 'UTF-8') - 1) NL ; -1 to exclude the terminating \0
response .= NL
response .= content
buf := Buffer(StrPut(response, 'UTF-8') - 1)
StrPut(response, buf, 'UTF-8')
this.sock.Send(buf)
}
}
class HTTPServer {
paths := Map()
__Item[name] {
get => this.paths[name]
set => this.paths[name] := value
}
_Callback(sock, event, err) {
switch event {
case 'Read':
request := ''
while true {
buf := sock.Recv()
if !buf.Size
break
request .= StrGet(buf, 'UTF-8')
}
if request {
request := HTTPRequest(request)
response := HTTPResponse(sock)
if (this.paths.Has(request.path)) {
this.paths[request.path](request, response)
} else {
response.Send(404, 'Not Found')
}
}
sock.Close()
}
}
Run(host := '127.0.0.1', port := 80) {
this.sock := winsock('server', this._Callback.Bind(this), 'IPV4')
this.sock.Bind(host, port)
this.sock.Listen()
}
}
Hello(request, response) {
response.Send(200, 'Hello World')
}
server := HTTPServer()
server['/'] := Hello
server.Run('127.0.0.1', 8001)
Re: Socket Class - 2022/09/07 - beta.8
Big Thanks for the winsock.
Start server:
Close server?
If start server again
I have Error:
WSAASyncSelect failed. Line: 287: (!block) ? this.RegisterEvents() : ""
Code RegisterEvents:
What I am wrong?
Start server:
Code: Select all
sock := winsock("server",cb,"IPV4")
sock.Bind("0.0.0.0",27015) ; "0.0.0.0",27015
sock.Listen()
Code: Select all
sock.close()
Code: Select all
sock := winsock("server",cb,"IPV4")
sock.Bind("0.0.0.0",27015) ; "0.0.0.0",27015
sock.Listen()
WSAASyncSelect failed. Line: 287: (!block) ? this.RegisterEvents() : ""
Code RegisterEvents:
Code: Select all
RegisterEvents(lEvent:=0x3FF) { ; FD_ALL_EVENTS = 0x3FF
this.block := !lEvent ? false : true
If (result:=this._WSAAsyncSelect(this.desc, A_ScriptHwnd, winsock.wm_msg, lEvent) = -1)
throw Error("WSAASyncSelect failed.", -1)
;If !lEvent
; result := this._ioctlsocket(this.desc, 0x8004667E, &r:=0) ; FIONBIO := 0x8004667E (non-blocking mode)
return !result
Re: Socket Class - 2022/09/07 - beta.8
And second question:
how to set "wait time" response from sever (for example - 20 milliseconds)?
how to set "wait time" response from sever (for example - 20 milliseconds)?
Re: Socket Class - 2022/09/07 - beta.8
@Black_dog
Thanks for the post, I'll look into it.
In case you have more time to experiment before I get to it, my first thought is that maybe the port is no longer open? But I don't actually have a method that will check for specific port availability currently. That is a loose "To-Do" item.
Thanks for the post, I'll look into it.
In case you have more time to experiment before I get to it, my first thought is that maybe the port is no longer open? But I don't actually have a method that will check for specific port availability currently. That is a loose "To-Do" item.
« AHK Portable Installer » | « CallTipsForAll » | « TheArkive AHK v1 Scripts » | « TheArkive AHK v2 Scrpts » | « TheArkive on GitHub »