1

Тема: JScript: Метод GetData в WinSock Control

Здравствуйте, товарищи.

Потребовалось реализовать межпроцессное взаимодействие с помощью сокетов. Используется компонент MSWinsock.Winsock. Обнаружил на форуме несколько примеров на VBscript. Переписал на JScript

Server.js

var Winsock = new ActiveXObject("MSWinsock.Winsock")
var bClose = true

function Winsock_ConnectionRequest(reqId)
{
Winsock.Close()
Winsock.Accept(reqId)
}

function Winsock_DataArrival(bytTotal)
{
var Data
Data = ""
Winsock.GetData(Data,8,bytTotal)
WScript.Echo("[Сервер] Получено: "+Data)
Winsock.SendData("Привет от сервера :) ")
}

function Winsock_Error(number, desc, sCode, src, help, helpctx, cancelDisplay)
{
WScript.Echo("[Сервер] Ошибка: "+desc)
bClose = false
}

function Winsock_Close()
{
WScript.Echo("Соединение закрыто.")
bClose=false
}

WScript.ConnectObject(Winsock,"Winsock_")   
Winsock.LocalPort = 6789
Winsock.Protocol = 0
Winsock.Listen()  
while(bClose) 
{
WScript.Sleep(500)
}

Client.js

var bConnected =false
var bSent=false
var bDataReceived=false
var Winsock= new ActiveXObject("MSWinsock.Winsock")

function Winsock_Connect()
{
bConnected=true
}

function Winsock_SendComplete()
{
bSent=true
}

function Winsock_DataArrival(bytTotal)
{
var str
Winsock.GetData(str)
WScript.Echo("[Клиент] Получено: " + str)
bDataReceived=true
}

WScript.ConnectObject(Winsock,"Winsock_")
Winsock.Connect("127.0.0.1",6789)
while (!bConnected)
{
WScript.Sleep(500)
}
   
Winsock.SendData("Привет, сервер!")
   
while(!bDataReceived)
{
WScript.Sleep (500)
}
Winsock.Close()

При запуске Server.vbs + Client.js получаю последовательность сообщений: "[Сервер] Получено: Привет, сервер!" - "[Клиент] Получено: undefined" - "Соединение закрыто."
При запуске Server.js + Client.vbs: "[Сервер] Получено: " - "[Клиент] Получено: Привет от сервера " - "Соединение закрыто."
При запуске Server.js + Client.js: "[Сервер] Получено: " - "[Клиент] Получено: undefined" - "Соединение закрыто."

По сему видно, что в коде JScript метод GetData отрабатывает некорректно (содержимое буфера сокета не присваивается переменной)
Посмотрел здесь, поколдовал с параметром type, но эффекта это не дало.
Код на VBScript был взят здесь

Сведущие граждане, помогите разобраться, пожалуйста.

2

Re: JScript: Метод GetData в WinSock Control

Предполагаю, что проблема в совместимости JS с Winsock. На сколько я помню, уважаемый коллега JSman, сталкивался с этим. А вариант передачи любых (доступных скриптам) типов данных между процессами не через winsock не заинтересовал ? Я об этом: WSH: обмен данными и объектами между скриптами — 2

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

3 (изменено: Himmler, 2012-01-19 19:11:53)

Re: JScript: Метод GetData в WinSock Control

Дело в том, что взаимодействие требуется реализовать именно с помощью сокетов. Это я для тестирования взял Server.js и Client.js, а на деле взаимодействие будет происходить не между двумя скриптами, а между скриптом и готовой программой (которая уже написана и использует сокеты). Кроме того, требуется возможность взаимодействия не только в пределах локалхоста. Возможно, тов. JSman сможет прояснить ситуацию.

4

Re: JScript: Метод GetData в WinSock Control

Предположу, что GetData сам создаёт строку, заполняет её, а указатель на неё должен положить в переменную, ссылка на которую передаётся ему в первом параметре. Но в JScript переменные в метод передаются по значению, а не по ссылке, поэтому и облом.

Раз метод не ругается на не тот тип параметра, то, возможно, происходит преобразование типа и он таки получает ссылку, но не на оригинал переменной, а на её временную копию, переданную из JScript. Ведь передача по значению — это передача копий. Он помещает указатель на строку в эту копию, но она никак не доступна из скрипта и перестаёт существовать после вызова.

5

Re: JScript: Метод GetData в WinSock Control

В крайнем случае можно оставить кусок на VBScript и передавать результаты из него в основной код на JScript (ибо всё будет в hta), но это очень уж криво. Хотелось бы без подобных костылей.

6 (изменено: max7, 2012-01-20 01:21:22)

Re: JScript: Метод GetData в WinSock Control

YMP абсолютно прав.
Проблема решается только через VBS и WSF по образцу

Фаил WSF:

<?xml version="1.0"?>
<package>
   <job id="default">
      <description>Launch JS File</description>
      <script language="VBScript" src="vbs-wrappers.vbs"/>
      <script language="JScript" src="app.js"/> 
   </job>
</package>

Фаил vbs-wrappers.vbs:

Function VBS_Wrapper_Winsock_GetData(byref sock, datatype)
   Dim buf
   sock.GetData buf, datatype
   VBS_Wrapper_Winsock_GetData = buf 
   Exit Function
End Function

Function VBS_Wrapper_Winsock_SendData(byref sock, datatype, data)
   Dim buf
   buf = data
   sock.SendData buf, datatype
   Exit Function
End Function

Function VBS_Wrapper_Winsock_PeekData(byref sock, datatype, data)
   Dim buf
   buf = data
   sock.PeekData buf, datatype
   Exit Function
End Function

Function VBS_Wrapper_Winsock_CancelDisplay(byref cancelDisplay)
   cancelDisplay = True
   Exit Function
End Function

Фаил app.js:

/*здесь ваш код, что-то по типу этого*/
...
function Winsock_DataArrival(bytTotal)
{
var str = VBS_Wrapper_Winsock_GetData(Winsock, /*VariantType.vbString*/ 8);
WScript.Echo("[Клиент] Получено: " + str)
bDataReceived=true
}
...

7

Re: JScript: Метод GetData в WinSock Control

Это, конечно, костыль. Но если других вариантов нету, придётся делать так.

8

Re: JScript: Метод GetData в WinSock Control

Приветствую. Поднял старую темку из архива:
JScript: Оконное приложение с графическими ресурсами в одном JS-файле. Видно поленился добавлять в коллекцию.
В ней как раз демонстрируется работа с WinSock из JScript. Что касается причин такого поведения, то лучше всего их разъяснил уважаемый коллега YMP.

var VB = new ActiveXObject("htmlfile").parentWindow;    
VB.document.write("<script language='VBScript'>Function GetData(Obj, data, num, bytTotal)\nObj.GetData data, num, bytTotal\nGetData = data\nEnd Function</script>");
var 
    Port = parseInt(Math.random()*100000)% 20000 +9000,
    MainSocket = WScript.CreateObject("MSWinsock.Winsock.1","MainSocket_"),
    Sockets = {};
    MainSocket.LocalPort = Port;
    MainSocket.Listen();
    
Function.prototype.GetResource = function (ResourceName)
{
    if (!this.Resources) 
    {
        var UnNamedResourceIndex = 0, _this = this;
        this.Resources = {};
        function f(match, resType, Content){
            _this.Resources[(resType=="[[")?UnNamedResourceIndex++:resType.slice(1,-1)] = Content;}
        this.toString().replace(/\/\*(\[(?:[^\[]+)?\[)((?:[\r\n]|.)*?)\]\]\*\//gi, f);
    }
    return this.Resources[ResourceName];
}

function GetResource(ResourceName) {
    return arguments.callee.caller.GetResource(ResourceName)}
    
function DecodeBase64(textBase64)
{
var Element = new ActiveXObject("MSXml2.DOMDocument").createElement("tmp");
    Element.dataType = "bin.base64";
    Element.text = textBase64;
    return Element.nodeTypedValue;
}

function HTTPGetFileName(Data)
{
    var match = Data.match(/^(\w+)\s+\/([^\s]*)\s+([^\s]+)/);
    return (match && match[2])? match[2] : null;
}

var Host = this;

function CreateWindow(content, x, y, width, height)
{
var HTASettings = "", e, window; 

    try {HTASettings = content.match(/<hta[^>]+>/gim)[0].replace(/\r?\n/g, " ").replace(/"/g,"'")} catch (e){};
    
var 
    ID = (new Date).valueOf(),
    CodeForLinking = "\"<script>moveTo(-300,-300); resizeTo(0,0)</script>"+HTASettings+"<object id="+ID+" classid='clsid:8856F961-340A-11D0-A96B-00C04FD705A2'><param name=RegisterAsBrowser value=1></object>\"",
    ShellWindows=(new ActiveXObject("Shell.Application")).Windows(),
    NumberOfWindows = ShellWindows.Count;

    (new ActiveXObject("WScript.Shell")).Run("mshta.exe javascript:"+CodeForLinking);
    while (NumberOfWindows==ShellWindows.Count) {WScript.Sleep(10);}

    for (var i=ShellWindows.Count; --i>=0;)
       if  (ShellWindows.Item(i).id == ID) 
       window = ShellWindows.Item(i).parent.parentWindow;
    
    try
    {
        window.document.open();
        window.document.write("<base href='http://localhost:"+Port+"/' >"+(content || "") + "<script language='JScript'>eval</script>");
        window.document.close();
        window.Host = Host;
        window.moveTo(Number(x) || 0, Number(y) || 0); 
        window.resizeTo(Number(width) || 400, Number(height) || 300); 
    }
    catch (e) {return}
    return window;
}

function MainSocket_ConnectionRequest(requestID)
{
    var NewSocket = WScript.CreateObject("MSWinsock.Winsock","Socket_");
    NewSocket.Accept(requestID);
    Sockets[NewSocket.SocketHandle]=NewSocket;
}

function Socket_SendComplete()
{
    delete Sockets[this.SocketHandle];
    this.Close();
    WScript.DisconnectObject(this);
}

function Socket_DataArrival(bytTotal)
{
  var Data = VB.GetData (this, Data, 8, bytTotal);
  var FileName = HTTPGetFileName(Data);

  if (Resources.GetResource(FileName))
  {
    this.SendData("HTTP/1.1 200 OK\nContent-Type: application/octet\nContent-Transfer-Encoding: binary\nContent-Disposition: inline\n\n");
    this.SendData(DecodeBase64(Resources.GetResource(FileName)));
  }
  else this.SendData("HTTP/1.1 404 Not Found");
}
//——————————————————————————————————————————
function Resources()
{
/*[pic[iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADYUExURWJiYv7xQ0ZGRioqKiQaAP/te//gAPeiAP7uZP7lAP/YAPz8Ef/UAP31Kv+zAP7qADcuFf+6APOgAP3yAP/dAP33AP/MAP/VZemdAP3yAf+sAP/eQsaHAP7sEf30Ef/gY//DIP/VVtaeLkM9If7MYv31Jv/jVv/AEf7tKt6jMeCpAOXNJ/GfAP/BAPz5AOfQOf7jGfikAP/dAf/he/33Af7kEf/FKv/aEf/IRv/FPv7lAv7xYv/WCv/jDvixKuSkGfW5Rf7qAuOgDvmqEf/cKuKbAAAAAP///7GsR/gAAABIdFJOU///////////////////////////////////////////////////////////////////////////////////////////////AJzs8mAAAACwSURBVHjaVM9FFsMwDARQBxpmhqbMzMytlfvfqHbSTedpob/SCOU0QFNsiKqd9urNowWlYS5VSNbhEKhhLJ0RkhAKOy0gthiGYVky6eFh5QgWA13nODKf3e0OCK5ZTVXVWrbd998vYsHs+jPfNQWtIWJiT4aN65qyd4EJtSLIEMfP0wqSiDjnFU8o+hkO5un9UaApWjA1RFyFoh+2bdtIHMqyP78UnQjzv/5//30FGACrUSaRymhFqgAAAABJRU5ErkJggg==]]*/

/*[HTML[
<html><title>Гипертекстовое приложение</title><body>Привет от JSman! <img src='pic' /></body></html>
]]*/
}

var window = CreateWindow(Resources.GetResource("HTML"), 200, 200, 350, 100);

while ((typeof window.document)=="object") WScript.Sleep(10);

9

Re: JScript: Метод GetData в WinSock Control

JSman пишет:

Поднял старую темку из архива:

Поднял тему из архива в Разработку. Теперь она доступна и участникам.

JSman пишет:

Видно поленился добавлять в коллекцию.

Есть повод .

10

Re: JScript: Метод GetData в WinSock Control

Досадно, конечно, но лучше уж криво, чем никак. Значит будет с куском VBScript.

11

Re: JScript: Метод GetData в WinSock Control

Так, опять упёрся. Насколько я понимаю, ввиду отсутствия возможности вызова внутри hta метода WScript.ConnectObject() повесить свои обработчики событий на Winsock не получится, и придётся делать через одно место, вроде как здесь.
Если всё действительно так коряво, то нет ли альтернативы MSWinsock.Winsock ? Ибо такое извращение это уже слишком.

12

Re: JScript: Метод GetData в WinSock Control

Himmler, соберите просто свой WSC внутри с обработкой событий винсока. Просто и удобно. И работать будет и в VBS и в JS. Да и подключать события потом проще. А вообще переходите лучше на VBS. )

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

13

Re: JScript: Метод GetData в WinSock Control

Himmler, коллега, я Вам код привел, который позволяет не только работать с винсоком, но и с HTA с возможностью транслирования объекта Wscript.  Предлагаю еще раз обратить внимание на код. Что касается WSC считаю нецелесообразным его использование.

14

Re: JScript: Метод GetData в WinSock Control

про хта и события активиксов

<html>
<script type='text/vbscript'>
    function xgetdata(x)
        dim ret
        x.GetData ret, 8
        xgetdata=ret
    end function
</script>

<script type='text/javascript'>
var Winsock;
window.onload=function()
{
    function mswinsock::Connect()
    {
        Winsock.SendData("Привет, сервер!");
    }

    function mswinsock::DataArrival(bytTotal)
    {
        var str=xgetdata(Winsock);
        document.getElementById('get').innerHTML="[Клиент] Получено: " + str;
        Winsock.Close();
    }

    function mswinsock::SendComplete()
    {
    }

    Winsock = document.getElementById("mswinsock").object;
    Winsock.Connect("127.0.0.1",6789);
}
</script>
<body>
<object id='mswinsock' classid="clsid:248DD896-BB45-11CF-9ABC-0080C7E7B78D">
</object>
<div id='get'>
</div>
</body>
</html>
Я конечно далек от мысли... (с)

15

Re: JScript: Метод GetData в WinSock Control

smaharbA, практически идеальное решение, большое спасибо. Кусок на VBScript это, конечно, не очень здорово, но всё-таки приемлемо.

P.S. Прошу прощения за большую задержку, сдавал криптографию, не было времени посетить форум.