Объект JCJSTcpServer это полнофункциональный многопоточный асинхронный TCP сервер с поддержкой защищенного соединения
В этом разделе перечислены свойства и методы объекта JCJSTcpServer плагина PluginNetwork
В JCJSTcpServer реализован протокол обмена jCjS,
гарантирующий неизменную доставку JS объектов между удаленными постами jCjS.
Для совместимости со сторонним ПО, предусмотрен режим raw.
Пример использования находится в каталоге stuff/tests/pluginNetwork/TCP_Srv
Пример использования:
// Загрузить плагин и Установить в JS конструторы объектов
post.loadPlugin('PluginNetwork').install(scriptEngine);
// Создать объект, к свойствам и
// методам которого можно обращаться в стиле Qt
var tcpServer = new JCJSTcpServer();
//свойство параметра чтение/запись:
// Чтение
var addr = tcpServer.listen_addr;
// Запись
var addr = '127.0.0.1';
tcpServer.listen_addr = addr;
String tcpServer.listen_addr Чтение/запись
Установить прослушиваемый ip адрес
Внимание!!!
запись возможна только перед tcpServer.serverStart() или после tcpServer.serverStop()
При установке автоматически устанавливается параметр tcpVer
var addr = tcpServer.listen_addr; // по умолчанию '0.0.0.0' (на всех интерфейсах) tcpServer.listen_addr = '127.0.0.1'; // установить прослушивание только на localhost
int tcpServer.listen_port Чтение/запись
Установить прослушиваемый порт
Внимание!!!
запись возможна только перед tcpServer.serverStart() или после tcpServer.serverStop()
var port = tcpServer.listen_port; // по умолчанию '0' (система выделит порт автоматически) tcpServer.listen_port = 8888; // установить прослушивающий порт
String Array() tcpServer.allAddresses только чтение
Запрос всех доступных в системе ip-адресов (всех интерфесов)
var allAddresses = tcpServer.allAddresses; // Массив строк ['127.0.0.1', '192.168.1.24', '10.7.12.25']
bool tcpServer.isWork только чтение
возвращает текущее состояние сервера
if(tcpServer.isWork) {
tcpServer.serverStop();
}
VariantList tcpServer.clientDescriptors только чтение
возвращает дескрипторы соединений
var clientDescriptors = tcpServer.clientDescriptors;
int tcpServer.clientCount только чтение
возвращает количество подключенных клиентов
var clientsCount = tcpServer.clientCount;
int tcpServer.maxClients Чтение/запись
Максимальное количество клиентов
var maxClients = tcpServer.maxClients; // по умолчанию 30 tcpServer.maxClients = 1; // ограничить одним соединением
StringList tcpServer.clientAddrs только чтение
возвращает адреса подключенных клиентов
var clientAddrs = tcpServer.clientAddrs;
int tcpServer.intrval чтение/запись
Интервал чтения из сокета
bool tcpServer.raw чтение/запись
Включение raw режима (по умолчанию выключен)
quint8 tcpServer.stopChar чтение/запись
В режиме raw: Символ конца приемной посылки (по умолчанию 0 - выключен)
String tcpServer.stopWord чтение/запись
В режиме raw: Слово конца приемной посылки (по умолчанию '' - выключен)
stopChar более приоритетнее чем stopWord
Параметры, относящиеся к конфигурированию защищенного соединения
bool tcpServer.ssl только чтение
возвращает текущий режим
var ssl = tcpServer.ssl;
Если сервер подключен в режиме без шифрования, а клиент пытается подключиться в режиме SSL, то в логе клиента вы встретите уведомление
2015-02-06-11:11:29.182 +1 TCP_Cli_00: error=13: Error during SSL handshake: unknown protocol
В этом случае необходимо переключить сервер в режим защищенного соединения или отключить шифрование на стороне клинета.
Если сервер подключен в режиме шифрования, а клиент пытается подключиться в обычном режиме, то в логе клиента вы найдете сообщение о дисконнекте
2015-02-06-11:18:37.468 +1 TCP_Cli_00: error=1: The remote host closed the connection
В этом случае необходимо перевести клинета на защищенное соединение или переключить сервер в режим без шифрования
Если сервер использует самоподписанные сертификаты, на стороне клиента в логе можно встретить следующюю запись
2015-02-06-11:18:37.468 +1 error=13: The host name did not match any of the valid hosts for this certificate
В этом случае на стороне клиента нужно включить режим игнорирования ошибок ignoreSelfSignSsl
String tcpServer.mode только чтение
возвращает текущий режим
var mode = tcpServer.mode; /* Возвратит варианты: "без шифрования" "SSL сервер" */
String tcpServer.verifyMode Чтение/запись
Верификация удаленного клиента
int tcpServer.tcpVer Чтение/запись
Установить необходимую версию TcpIp (по умолчанию 0 автоматичекий выбор)
Внимание!!!
Автоматически устанавливается перед пуском сервера или во время установки listen_addr или сертификата
Установка необходимой версии имеет смысл только если:
String tcpServer.sslProto чтение/запись
установить необходимый протокол шифрования (по умолчанию SecureProtocols - максимально безопасный)
Внимание!!! Устанавливать необходимй протокол шифрования следует перед serverStart()
Для просмотра протокола шифрования, используемого клиентом см. getSslProto()
String tcpServer.sslKeyPass Чтение/запись
Установить пароль к приватному ключу
Внимание!!! Параметр устанавливается когда сервер остановлен
var keyPass = tcpServer.sslKeyPass; keyPass = '9045271001' tcpServer.sslKeyPass = keyPass;
String tcpServer.sslDir Чтение/запись
Указать каталог, в котором лежат ключ и сертификат
String tcpServer.sslCertName Чтение/запись
Указать имя сертификата (каталог поиска sslDir по умолчанию ../etc/ssl относительно каталога с исполняемым файлом jCjS)
Необходимое условие - файл приватного ключа .key и сертификата .crt должны имет одно имя
Внимание!!! Параметр устанавливается когда сервер остановлен
При установке сертификата определяется кому выдан сертификат, и если это ip-адрес или localhost то
автоматически устанавливается параметр listen_addr и tcpVer
if(post.ssl.enable == 'true')
{
// сначало указать пароль для приватного ключа, если он зашифрован
tcpServer.sslKeyPass = '9045271001'
// будет произведен поиск localhost.crt и его ключа в tcpServer.sslDir или '../etc/ssl' если tcpServer.sslDir === ''
tcpServer.sslCertName = 'localhost'
// или указать каталог с ключами, но выбор имени используемого сертификата будет отсутствовать
tcpServer.sslDir = server.getAbsPath('../etc/ssl') // будет найдена первая пара .key .crt с одинаковым именем
// sslDir и sslCertName это два разных подхода к установке используемого сертификата
}
При подключении к серверу, использующего SSL соединение, в логе клиента можно найти такую запись
2015-02-05-19:58:40.991 +0 JCJSTcpClient: 127.0.0.1:54207 <-> 127.0.0.1:8001 используют защищенное соединение
Если необходимо сменить ключ и сертификат, воспользуйтес сценарием etc/ssl/create-keys.[cmd|sh]
Необходимое условие - OpenSSL должен быть установлен
Скачать OpenSSL можно здесь https://www.openssl.org/related/binaries.html
if(post.ssl.enable == 'true')
{
tcpServer.sslDir = server.getAbsPath('../etc/ssl')
tcpServer.sslKeyPass = '9045271001'
}
При подключении к серверу, использующего SSL соединение, в логе клиента можно найти такую запись
2015-02-05-19:58:40.991 +0 JCJSTcpClient: 127.0.0.1:54207 <-> 127.0.0.1:8001 используют защищенное соединение
void tcpServer.readyRead(Variant message, int socketDescriptor)
генерируется объектом JCJSTcpServer при успешном приеме сообщения
// подсоединить к сигналу readyRead функцию обработчик
tcpServer.readyRead.connect(function messageRead(mess, socketDesc){
post.log("i", 'Клиент прислал сообщение: ' + JSON.stringify(mess) + ' дескриптор соединения=' + socketDesc)
});
// эквивалентно следующей конструкции
function messageRead(mess, socketDesc){
post.log("i", 'Клиент прислал сообщение: ' + JSON.stringify(mess) + ' дескриптор соединения=' + socketDesc);
}
tcpServer.readyRead.connect(messageRead);
// =====================================
// следующее два тривиального примера: автоматически отправлять эхо-ответ
// 1
tcpServer.readyRead.connect(tcpServer.sendClient);
// 2
//чтобы передать объект this в функцию обработчик
tcpServer.readyRead.connect(tcpServer, function(mess, descrptr){
// здесь (this === tcpServer) = true
this.sendClient(mess, descrptr);
});
void tcpServer.connected(String addr, int port, int socketDescriptor) Сигнал
генерируется объектом JCJSTcpServer при успешном подсоединении клиента к серверу
// подсоединить к сигналу connected функцию обработчик
tcpServer.connected.connect(function clientConnected(addr, port, socketDesc){
post.log("i", 'Есть новое соединение: ip-addr=' + addr + ' port=' + port + ' дескриптор соединения=' + socketDesc)
});
void tcpServer.disconnected(String addr, int port, int socketDescriptor) Сигнал
генерируется объектом JCJSTcpServer при разъединении соединения с клиентом
// подсоединить к сигналу connected функцию обработчик
tcpServer.disconnected.connect(function clientDisconnected(addr, port, socketDesc){
post.log("i", 'Клиент отключился: ip-addr=' + addr + ' port=' + port + ' дескриптор соединения=' + socketDesc)
});
void tcpServer.error(String error, int socketDescriptor) Сигнал
генерируется объектом JCJSTcpServer при ошибках в сокете
// подсоединить к сигналу connected функцию обработчик
tcpServer.error.connect(function error(err, socketDesc){
post.log("i", 'Ошибка: err=' + err + ' дескриптор соединения=' + socketDesc)
});
void tcpServer.protoSelfChange(int socketDescriptor, newVer, oldVer) Сигнал
генерируется объектом JCJSTcpServer если в процессе обмена протокол был изменен
tcpServer.protoSelfChange.connect(function protoSelfChange(d, newVer, oldVer){
if(newVer === 0 && oldVer > 0) {
post.log('w', 'было понижение версии. Встроенное шифрование crypt отключено');
post.log('w', 'cli ' + d + ': '+JSON.stringify(tcpServer.clientInfo(d)) );
}
});
Date tcpServer.serverWorkTime() Функция
Время работы сервера
var serverWorkTime = tcpServer.serverWorkTime();
bool tcpServer.serverStart() Функция
Запустить сервер
tcpServer.serverStart();
bool tcpServer.serverStop() Функция
Остановить сервер
tcpServer.serverStop();
bool tcpServer.serverStartStop() Функция
поменять статус сервера на противоположный
tcpServer.serverStartStop();
void tcpServer.removeAllCliens() Функция
отключает всех клиентов
(у каждого подключенного клиента сгенерируется сигнал разрыва соединения)
tcpServer.removeAllCliens();
void tcpServer.removeClient(descriptor) Функция
отключает клиента по дискриптору
(у подключенного клиента сгенерируется сигнал разрыва соединения)
for(var i = 0; i < tcpServer.clientDescriptors.lenght; ++i)
{
tcpServer.removeClient(tcpServer.clientDescriptors[i]);
}
// этот код равноценен команде tcpServer.removeAllCliens()
void tcpServer.getSslProto(descriptor) Функция
Используемый клиентом протокол шифрования
for(var i = 0; i < tcpServer.clientDescriptors.lenght; ++i)
{
post.log('w', 'cli number ' + i + ': '+tcpServer.getSslProto(tcpServer.clientDescriptors[i]));
}
// --------------- ИЛИ ---------------
tcpServer.connected.connect(tcpServer, function connected(addr, port, socketDescriptor){
post.log("e", "" + addr + ":" + port +
" sslProto=" + this.getSslProto(socketDescriptor) +
" clientCount=" + this.clientCount);
});
tcpServer.disconnected.connect(tcpServer, function disconnected(addr, port, socketDescriptor){
post.log("e", "" + addr + ":" + port +
" sslProto=" + this.getSslProto(socketDescriptor) +
" clientCount=" + this.clientCount);
});
void tcpServer.clientInfo(descriptor) Функция
Информация о соединении ввиде объекта
var dAll = tcpServer.clientDescriptors;
//post.log('w', 'cli dAll: '+dAll);
while(dAll.length)
{
var d = dAll.shift();
post.log('w', 'cli ' + d + ': '+JSON.stringify(tcpServer.clientInfo(d)) );
}
// Выведет подробную информацию о соединении
// {
// addr: "10.7.97.115",
// port: 62027,
// sslAuth: "RSA",
// sslEncrypt: "AES(256)",
// sslKeyExch: "RSA",
// sslProto: "SSLv3"
// }
void tcpServer.sendAllClients(String mess) Функция
отправить всем подключенным клиентам сообщение
tcpServer.sendAllClients('Сообщение, для всех подключенных');
void tcpServer.sendClient(Variant mess, int socketDescriptor) Функция
отправить сообщение клиенту по дескриптору соединения
tcpServer.readyRead.connect(function messageRead(mess, socketDesc){
post.log("i", 'Клиент прислал сообщение: ' + JSON.stringify(mess) + ' дескриптор соединения=' + socketDesc);
tcpServer.sendClient('Сообщение для клиента, приславшего сообщение', socketDesc);
});
// равноценно следующей записи, но передается объект this в функцию обработчик
tcpServer.readyRead.connect(tcpServer, function messageRead(mess, socketDesc){
post.log("i", 'Клиент прислал сообщение: ' + JSON.stringify(mess) + ' дескриптор соединения=' + socketDesc);
// здесь (this === tcpServer) = true
this.sendClient('Сообщение для клиента, приславшего сообщение', socketDesc);
});
void tcpServer.getClient(int socketDescriptor) Функция
взять у сервера объект соединения по дескриптору соединения
tcpServer.readyRead.connect(tcpServer, function messageRead(mess, socketDesc){
post.log("i", 'Клиент прислал сообщение: ' + JSON.stringify(mess) + ' дескриптор соединения=' + socketDesc);
// здесь (this === tcpServer) = true
this.sendClient('Сообщение для клиента, приславшего сообщение', socketDesc);
});
// равноценно следующей записи, но запрашивается объект соединения
tcpServer.readyRead.connect(tcpServer, function messageRead(mess, socketDesc){
post.log("i", 'Клиент прислал сообщение: ' + JSON.stringify(mess) + ' дескриптор соединения=' + socketDesc);
// здесь (this === tcpServer) = true
var cli = this.getClient(socketDesc);
cli.sendMessage('Сообщение для клиента, приславшего сообщение');
});