В Интернете очень мало документации для работы с сокетами из WSH, а ведь это, под час очень удобное средство для обмена данными между скриптами, запущенными на разных компьютерах сети (либо через интернет), а так же через сокеты можно организовать многопоточность VBS/JS скриптов.
Работа с сокетами будет показана на создании своего собственного нативного HTTP сервера, который будет читать запрос от клиента (в данном случае обычного браузера) обрабатывать его, и на основе анализа выдавать клиенту (браузеру) HTML содержимое запрашиваемой страницы.
Что такое сокет? Сокет это прикладной интерфейс Windows разработанный для обмена данными между хостами по технологии клиент-сервер. Сокет - виртуальная коммуникационная точка которая единовременно, может работать либо на прием либо на передачу данных (иногда, ошибочно, сокетами называют айпи_узла:номер_порта, например 127.0.0.1:80, но это может быть применимо только для протокола IP). В процессе обмена как правило используются два сокета - сокет отправителя и сокет получателя. Хосты могут находиться либо в разных участках сети либо на одном компьютере.
Сразу оговорюсь, из на прямую из Jsript работать с сокетами нельзя, поэтому тут возможны 3 пути:
1.Регестрировать сторонний ActiveX контрол(ActiveX компонент) для работы с API Windows и работать с сокетами через API, что приемлемо но не очень просто и чисто.
2. Использовать MSWINSCK.OCX ActiveX контрол от Майкрософт (поставляется с VB и MS Office). Здесь вроде все нормально, но с одной оговоркой- Js, в силу своей ограниченности, не умеет работать с функцией GetData(), хотя если вы пишете сервер на VBS то все нормально, да и сам контрол требует лицензии.
3.Использовать сторонний контрол, методы которого нормально возвращают параметры в Jscript. Я для этой цели использовал OstroSoft Winsock component (oswinsck.dll) http://www.ostrosoft.com/oswinsck/oswinsck_javascript.asp, по ссылке описание компонента и инструкции по установке.
После установки компонента приступаем к написанию кода.
var bClose=true;
Переменная-флаг, с помощью которой будем следить за состоянием соединения.
function obInit()
{
oWinsock = new ActiveXObject("OSWINSCK.Winsock");
WScript.ConnectObject(oWinsock, "oWinsock_");
oWinsock.LocalPort=8080;//порт
oWinsock.Protocol=0;// протокол
oWinsock.Listen();// начинаем слушать порт
}
Создаем экземпляр объекта OSWINSCK.Winsock, присоединяемся к нему с целью предоставления доступа к своим событиям - _OnConnectionRequest, _OnDataArrival _Error, Winsock_Close. Далее устанавливаем протокол, порт и начинаем слушать порт (oWinsock.Listen) .
Далее- пишем функции реагирующие на события.
Функция создания соединения:
function oWinsock_OnConnectionRequest(reqId)
{
WScript.Echo("accepting request");
oWinsock.CloseWinsock();
// на всякий случай закрываем все подлючения
WScript.Echo(reqId);
oWinsock.Accept(reqId);
// начинаем соединение
}
После создания соединения управление передается функции для обмена данными.
function oWinsock_OnDataArrival(bytTotal)
{
WScript.Echo("Начинаем прием от клиента...");
var size=0, match1 ;
data= new String("");// буфер запроса получаемого от клиента
fcontent= new String("");// строки считанные с запрашиваемого файла
result= new String(""); // то что будем в результате отдавать клиенту (браузеру)
Объявляем переменные, создаем строковые объекты, давая интерпретатору понять что это именно строки, а не Variant как по умолчанию.
WScript.Echo(bytTotal);
data=oWinsock.GetDataBuffer();// получаем запрос клиента
Обращаю внимание на то, что переменная дата !обязательно! должна быть строкой, иначе могут возникнуть проблемы.
WScript.Echo(data);//выводим запрос клиента в консоль, для наглядности.
(!) Необходимо использовать именно csript.exe.
WScript.Echo("Прием закончен...");
//обрабатываем запрос
Запрос от клиента будет иметь похожий вид:
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-silverlight, application/msword, application/vnd.ms-powerpoint, application/vnd.ms-excel, */*
Referer: http://10.97.24.200:8080/page2.html
Accept-Language: ru
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.1)
Host: 10.97.24.200:8080
Connection: Keep-Alive
Пробуем его обработать регулярными выражениями, с целью – узнать запрашиваемую страницу на сервере.
(!) Здесь показан только пример, для полноценной работы необходим более детальный анализ заголовка, что выходит за рамки этой статьи.
match1=data.match(/GET[\s]\/(.*?)[\s]*?HTTP\/?/i);
WScript.Echo("REGEXP:"+match1[1]);
В match1 получаем имя файла вида page.html.
//обрабатываем запрос (конец)
if(match1[1]=="")
{
fcontent=getfile("index.html");
}
else
{
fcontent=getfile(match1[1]);
}
Вызываем ф-ю чтения таргет-файла (которую опишем ниже), если результат пустой – переправляем на главную страницу сайта (Index.html).
size=fcontent.lenght;
Здесь получаем размер возращаемой страницы, с целью вставки ее в заголовок ответа.
result="HTTP/1.0 200 OK\r\nServer: JscriptServer\r\nContent-Language: ru\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length:"+size+"\r\n\r\n";
result+=fcontent;
Формируем заголовок ответа. Опять же – Это Пример, на самом деле в зависимости от медиатипа файла нужно отдавать разные заголовки (Content-Type:{здесь вбивать медиатип согласно RFC} ). Будем считать что на нашем сервере хранится только текстовая информация, дописать для остальных медиатипов не сложно.
oWinsock.SendData(result );
Отсылаем данные клиенту.
oWinsock.CloseWinsock();
Закрываем коннект.
oWinsock = null;
Убиваем объект.
obInit();
Создаем объект заново, для выполнения последующего запроса.
}
Далее опишем ф-ю чтения запрашиваемого файла.
function getfile(file)
{
FSO= new ActiveXObject("Scripting.FileSystemObject");
try
{
fl=FSO.OpenTextFile(file,1);
resfile =fl.ReadAll();
fl=null;
}
catch(e)
{
if(e!=0)
{
fl=FSO.OpenTextFile("404.html",1);
resfile =fl.ReadAll();
}
}
return (resfile);
}
Замечу что просто чтение файла 404 страницы тут НЕ корректно, ибо надо менять в самом заголовке result="HTTP/1.0 200…
Остается только контроль ошибок и проверка соединения.
function oWinsock_Error(number, desc, sCode, src, help, helpctx, cancelDisplay)
{
WScript.Echo("Error: "+desc);
bClose=false;
}
function oWinsock_Close()
{
WScript.Echo("Connection closed.");
bClose=false;
}
obInit();
while(bClose)WScript.Sleep(1);
Чем меньше значение WScript.Sleep(1); тем чаще сервер будет обрабатывать запросы. В остальном вроде все понятно.
Осталось создать страницы в корне нашего сервера и запустить скрипт.

В строке браузера набираем Http://127.0.0.1:8080 видим следующую картину:
Естественно, данный пример не выдержит, большое число запросов, и не обладает многопоточностью, но вполне работоспособен. Скрипт можно доработать добавив Mime типы, кеширование, многопоточность, поддержку динамических страниц и т д..
Готовый скрипт можно скачать здесь.