Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Socket Class (überarbeitet)


  • Please log in to reply
30 replies to this topic
Bentschi
  • Moderators
  • 120 posts
  • Last active: Sep 05 2014 02:12 AM
  • Joined: 26 Nov 2008

Hallo
Hab die Socket-Classen von http://www.autohotke...opic.php?t=8587 nochmal überarbeitet.
 
Änderungen:
- Hauptklasse Socket erstellt
- TCP Klasse in SocketTCP umbenannt
- UDP Klasse in SocketUDP umbenannt
- send in sendText umbenannt
- sendBinary in send umbenannt
- recv in recvText umbenannt
- recvBinary in recv umbenannt
- Callbackreferenzen werden jetzt mit bsp. mySocket.onRecv := Func("MyOnRecv") erstellt

- Einige Fehler und Probleme behoben und verbessert

class Socket
{
  static __eventMsg := 0x9987
  
  __New(s=-1)
  {
    static init
    if (!init)
    {
      DllCall("LoadLibrary", "str", "ws2_32", "ptr")
      VarSetCapacity(wsadata, 394+A_PtrSize)
      DllCall("ws2_32\WSAStartup", "ushort", 0x0000, "ptr", &wsadata)
      DllCall("ws2_32\WSAStartup", "ushort", NumGet(wsadata, 2, "ushort"), "ptr", &wsadata)
      OnMessage(Socket.__eventMsg, "SocketEventProc")
      init := 1
    }
    this.socket := s
  }
  __Delete()
  {
    this.disconnect()
  }
  __Get(k, v)
  {
    if (k="size")
      return this.msgSize()
  }
  connect(host, port)
  {
    if ((this.socket!=-1) || (!(faddr := next := this.__getAddrInfo(host, port))))
      return 0
    while (next)
    {
      sockaddrlen := NumGet(next+0, 16, "uint")
      sockaddr := NumGet(next+0, 16+(2*A_PtrSize), "ptr")
      if ((this.socket := DllCall("ws2_32\socket", "int", NumGet(next+0, 4, "int"), "int", this.__socketType, "int", this.__protocolId, "ptr"))!=-1)
      {
        if ((r := DllCall("ws2_32\WSAConnect", "ptr", this.socket, "ptr", sockaddr, "uint", sockaddrlen, "ptr", 0, "ptr", 0, "ptr", 0, "ptr", 0, "int"))=0)
        {
          DllCall("ws2_32\freeaddrinfo", "ptr", faddr)
          return Socket.__eventProcRegister(this, 0x21)
        }
        this.disconnect()
      }
      next := NumGet(next+0, 16+(3*A_PtrSize), "ptr")
    }
    this.lastError := DllCall("ws2_32\WSAGetLastError")
    return 0
  }
  bind(host, port)
  {
    if ((this.socket!=-1) || (!(faddr := next := this.__getAddrInfo(host, port))))
      return 0
    while (next)
    {
      sockaddrlen := NumGet(next+0, 16, "uint")
      sockaddr := NumGet(next+0, 16+(2*A_PtrSize), "ptr")
      if ((this.socket := DllCall("ws2_32\socket", "int", NumGet(next+0, 4, "int"), "int", this.__socketType, "int", this.__protocolId, "ptr"))!=-1)
      {
        if (DllCall("ws2_32\bind", "ptr", this.socket, "ptr", sockaddr, "uint", sockaddrlen, "int")=0)
        {
          DllCall("ws2_32\freeaddrinfo", "ptr", faddr)
          return Socket.__eventProcRegister(this, 0x29)
        }
        this.disconnect()
      }
      next := NumGet(next+0, 16+(3*A_PtrSize), "ptr")
    }
    this.lastError := DllCall("ws2_32\WSAGetLastError")
    return 0
  }
  listen(backlog=32)
  {
    return (DllCall("ws2_32\listen", "ptr", this.socket, "int", backlog)=0) ? 1 : 0
  }
  accept()
  {
    if ((s := DllCall("ws2_32\accept", "ptr", this.socket, "ptr", 0, "int", 0, "ptr"))!=-1)
    {
      newsock := new Socket(s)
      newsock.__protocolId := this.__protocolId
      newsock.__socketType := this.__socketType
      Socket.__eventProcRegister(newsock, 0x21)
      return newsock
    }
    return 0
  }
  disconnect()
  {
    Socket.__eventProcUnregister(this)
    DllCall("ws2_32\closesocket", "ptr", this.socket, "int")
    this.socket := -1
    return 1
  }
  msgSize()
  {
    VarSetCapacity(argp, 4, 0)
    if (DllCall("ws2_32\ioctlsocket", "ptr", this.socket, "uint", 0x4004667F, "ptr", &argp)!=0)
      return 0
    return NumGet(argp, 0, "int")
  }
  send(addr, length)
  {
    if ((r := DllCall("ws2_32\send", "ptr", this.socket, "ptr", addr, "int", length, "int", 0, "int"))<=0)
      return 0
    return r
  }
  sendText(msg, encoding="UTF-8")
  {
    VarSetCapacity(buffer, length := (StrPut(msg, encoding)*(((encoding="utf-16")||(encoding="cp1200")) ? 2 : 1)))
    StrPut(msg, &buffer, encoding)
    return this.send(&buffer, length)
  }
  recv(byref buffer, wait=1)
  {
    while ((wait) && ((length := this.msgSize())=0))
      sleep, 100
    if (length)
    {
      VarSetCapacity(buffer, length)
      if ((r := DllCall("ws2_32\recv", "ptr", this.socket, "ptr", &buffer, "int", length, "int", 0))<=0)
        return 0
      return r
    }
    return 0
  }
  recvText(wait=1, encoding="UTF-8")
  {
    if (length := this.recv(buffer, wait))
      return StrGet(&buffer, length, encoding)
    return
  }
  __getAddrInfo(host, port)
  {
    a := ["127.0.0.1", "0.0.0.0", "255.255.255.255", "::1", "::", "FF00::"]
    conv := {localhost:a[1], addr_loopback:a[1], inaddr_loopback:a[1], addr_any:a[2], inaddr_any:a[2], addr_broadcast:a[3]
    , inaddr_broadcast:a[3], addr_none:a[3], inaddr_none:a[3], localhost6:a[4], addr_loopback6:a[4], inaddr_loopback6:a[4]
    , addr_any6:a[5], inaddr_any:a[5], addr_broadcast6:a[6], inaddr_broadcast6:a[6], addr_none6:a[6], inaddr_none6:a[6]}
    if (conv[host])
      host := conv[host]
    VarSetCapacity(hints, 16+(4*A_PtrSize), 0)
    NumPut(this.__socketType, hints, 8, "int")
    NumPut(this.__protocolId, hints, 12, "int")
    if ((r := DllCall("ws2_32\getaddrinfo", "astr", host, "astr", port, "ptr", &hints, "ptr*", next))!=0)
    {
      this.lastError := DllCall("ws2_32\WSAGetLastError")
      return 0
    }
    return next
  }
  __eventProcRegister(obj, msg)
  {
    a := SocketEventProc(0, 0, "register", 0)
    a[obj.socket] := obj
    return (DllCall("ws2_32\WSAAsyncSelect", "ptr", obj.socket, "ptr", A_ScriptHwnd, "uint", Socket.__eventMsg, "uint", msg)=0) ? 1 : 0
  }
  __eventProcUnregister(obj)
  {
    a := SocketEventProc(0, 0, "register", 0)
    a.remove(obj.socket)
    return (DllCall("ws2_32\WSAAsyncSelect", "ptr", obj.socket, "ptr", A_ScriptHwnd, "uint", 0, "uint", 0)=0) ? 1 : 0
  }
}
SocketEventProc(wParam, lParam, msg, hwnd)
{
  global Socket
  static a := []
  Critical
  if (msg="register")
    return a
  if (msg=Socket.__eventMsg)
  {
    if (!isobject(a[wParam]))
      return 0
    if ((lParam & 0xFFFF) = 1)
      return a[wParam].onRecv(a[wParam])
    else if ((lParam & 0xFFFF) = 8)
      return a[wParam].onAccept(a[wParam])
    else if ((lParam & 0xFFFF) = 32)
    {
      a[wParam].socket := -1
      return a[wParam].onDisconnect(a[wParam])
    }
    return 0
  }
  return 0
}

class SocketTCP extends Socket
{
  static __protocolId := 6 ;IPPROTO_TCP
  static __socketType := 1 ;SOCK_STREAM
}

class SocketUDP extends Socket
{
  static __protocolId := 17 ;IPPROTO_UDP
  static __socketType := 2 ;SOCK_DGRAM

  enableBroadcast()
  {
    VarSetCapacity(optval, 4, 0)
    NumPut(1, optval, 0, "uint")
    if (DllCall("ws2_32\setsockopt", "ptr", this.socket, "int", 0xFFFF, "int", 0x0020, "ptr", &optval, "int", 4)=0)
      return 1
    return 0
  }
  disableBroadcast()
  {
    VarSetCapacity(optval, 4, 0)
    if (DllCall("ws2_32\setsockopt", "ptr", this.socket, "int", 0xFFFF, "int", 0x0020, "ptr", &optval, "int", 4)=0)
      return 1
    return 0
  }
}


nnnik
  • Members
  • 1625 posts
  • Last active: Apr 11 2017 02:13 PM
  • Joined: 28 Jul 2012
Nicht schlecht. grin.png

Visit the new forum ahkscript.org.

http://ahkscript.org


strobo
  • Members
  • 359 posts
  • Last active: Mar 10 2015 08:13 PM
  • Joined: 19 Jun 2012

Ich bin grad bei deiner lib am rumtesten und funzt soweit gut.
Kleiner typo in __getAddrInfo:

inaddr_any:5[5]
 
Regards,
Babba

Bentschi
  • Moderators
  • 120 posts
  • Last active: Sep 05 2014 02:12 AM
  • Joined: 26 Nov 2008

danke dir, ist geändert



Larctic
  • Members
  • 303 posts
  • Last active: May 10 2016 04:56 PM
  • Joined: 21 Jul 2012

Can you please write some examples of it?



nnnik
  • Members
  • 1625 posts
  • Last active: Apr 11 2017 02:13 PM
  • Joined: 28 Jul 2012
myTcp := new tcp() ;myTcp is the new tcp-Objekt (class)
myTcp.accept("addr_any", 12345) ;Waiting for Connection on Port 12345
myTcp.send("Hello Client!") ;Send Text-Message
MsgBox, % myTcp.recv() ;Getting Text-Message
ExitApp

This is an example for the original Version of the Script.

Wich you can find in the Link.

 

 

BTW wie muss ich denn diese Zeile abändern Bentschi:

myTcp.accept("addr_any", 12345) 

Visit the new forum ahkscript.org.

http://ahkscript.org


Bentschi
  • Moderators
  • 120 posts
  • Last active: Sep 05 2014 02:12 AM
  • Joined: 26 Nov 2008

sorry, hab ich wohl vergessen, mit der neuen Version funktioniert das nur noch mit den callbacks (onAccept)



SAPlayer
  • Members
  • 403 posts
  • Last active: Apr 11 2014 04:45 PM
  • Joined: 06 Nov 2012
Habe mich mal gewagt das Beispiel von oben umzuschreiben, allerdings ungetestet:

myTcp := new SocketTCP()
myTcp.onAccept := Func("OnTCPAccept")
return

OnTCPAccept(){
  global myTcp
  myTcp.sendText("Hello Client!")
  MsgBox, % myTcp.recvText()
  ExitApp
}
Bitte verbessert mich falls was nicht passt...

Bentschi
  • Moderators
  • 120 posts
  • Last active: Sep 05 2014 02:12 AM
  • Joined: 26 Nov 2008

ja, erst must du den socket binden (bind), und dann auf verbindung warten (listen), und dann noch akzeptieren (accept)

myTcp := new SocketTCP()
myTcp.bind("addr_any", 12345)
myTcp.listen()
myTcp.onAccept := Func("OnTCPAccept")
return

OnTCPAccept(){
  global myTcp
  newTcp := myTcp.accept()
  newTcp.sendText("Hello Client!")
  MsgBox, % newTcp.recvText()
  ExitApp
}

sollte funktionieren



SAPlayer
  • Members
  • 403 posts
  • Last active: Apr 11 2014 04:45 PM
  • Joined: 06 Nov 2012
Okay danke, ich werde das morgen mal probieren.

Nochmal eine kleine Frage:
Gibt es sowas wie SendAllClients?

Bentschi
  • Moderators
  • 120 posts
  • Last active: Sep 05 2014 02:12 AM
  • Joined: 26 Nov 2008
myTcp := new SocketTCP()
myTcp.bind("addr_any", 12345)
myTcp.listen()
clients := []
myTcp.onAccept := Func("OnTCPAccept")
return

OnTCPAccept(){
global myTcp
clients.insert(myTcp.accept())
}

SendToAll(msg)
{
  global clients
  for k,v in clients
    v.send(msg)
}


SAPlayer
  • Members
  • 403 posts
  • Last active: Apr 11 2014 04:45 PM
  • Joined: 06 Nov 2012

Gut, ich habe jetzt die beiden TCP-Beispiele (Client und Server) aus dem alten Thread an die überarbeitete Class angepasst (getestet):

;Server

myTcp := new SocketTCP()
myTcp.bind("addr_any", 12345)
myTcp.listen()
myTcp.onAccept := Func("OnTCPAccept")
return

OnTCPAccept(){
  global myTcp
  newTcp := myTcp.accept()
  newTcp.sendText("Hello Client!")
  MsgBox, % newTcp.recvText()
  ExitApp
}
;Client

myTcp := new SocketTCP()
myTcp.connect("localhost", 12345)
MsgBox, % myTcp.recvText()
myTcp.sendText("Hello Server!")
ExitApp

Die kannst du ja vielleicht in den Post einfügen.

Eventuell mach ich jetzt auch noch die anderen Beispiele ;)



Larctic
  • Members
  • 303 posts
  • Last active: May 10 2016 04:56 PM
  • Joined: 21 Jul 2012
Very grateful,Examples useful to me.


SAPlayer
  • Members
  • 403 posts
  • Last active: Apr 11 2014 04:45 PM
  • Joined: 06 Nov 2012

Gut, nun wollte ich einen kleinen (recht sinnlosen) Chat aufbauen, doch leider krieg ich auch das nur zur Hälfte gebacken:

;Server

myTcp := new SocketTCP()
myTcp.bind("addr_any", 12345)
myTcp.listen()
myTcp.onAccept := Func("OnTCPAccept")
return

OnTCPAccept(this){
  newTcp := this.accept()
  newTcp.sendText("Connected")
  newTcp.onRecv := Func("OnTCPRecv")
}
OnTCPRecv(this){
  InputBox, msg, Server to Client Message, % "Message from Client:`n" this.RecvText()
  this.SendText(msg)
}
;Client

myTcp := new SocketTCP()
myTcp.connect("localhost", 12345)
myTcp.onRecv := Func("OnTCPRecv")
return

OnTCPRecv(this){
	InputBox, msg, Client to Server Message, % "Message from Server:`n" this.RecvText()
	this.SendText(msg)
}

Das Problem hierbei ist, dass die "Connected"-Meldung zwar beim Client ankommt, jedoch kommt dann die Eingabe in der InputBox nicht mehr beim Server an...



clackwell
  • Members
  • 2 posts
  • Last active: Oct 27 2013 07:25 PM
  • Joined: 26 Oct 2013

Hallo.

 

Ich habe das gleiche Problem wie SAPlayer.

 

Das Problem ist vermutlich, dass für die accept()ed Socket das Event Processing nicht aktiviert wird. Hier die korrigierte accept() Methode:

 

  accept()
  {
    if ((s := DllCall("ws2_32\accept", "ptr", this.socket, "ptr", 0, "int", 0, "ptr"))!=-1)
    {
      newsock := new Socket(s)
      newsock.__protocolId := this.__protocolId
      newsock.__socketType := this.__socketType
      Socket.__eventProcRegister(newsock, 0x21)
      return newsock
    }
    return 0
  }
 
(Neu ist die Zeile Socket.__eventProcRegister(newsock, 0x21)).
 
 
 
Ciao