Хорошо, я решил, что хочу сам протестировать сокеты Haxe SSL.Из-за большого количества предостережений это, вероятно, не будет решением вашей проблемы, но, возможно, некоторые из них помогут.И начинать с «что-то, что работает» лучше, чем ничего!
Во-первых, я нахожусь на Linux.Я обнаружил, что сокеты (и потоки) могут демонстрировать другое поведение и проблемы в Windows, чем в Linux / OSX.
Во-вторых, я сначала пробую это с допустимым именем хоста.Я никогда не использовал SSL на localhost
и хотел удалить все неизвестные.Так что у меня есть действующий сертификат / ключ, который я использую.В приведенном ниже коде это называется foo.example.com
.Вы можете получить бесплатный сертификат для домена, которым вы владеете, по адресу letsencrypt.org .
В-третьих, я столкнулся с проблемой в библиотеке Haxe std.Чтобы обойти это, я просто изменил строку 17 в haxe/std/cpp/_std/sys/ssl/Key.hx
:
var str = data.toString(); // cpp.Lib.stringReference(data);
В-четвертых, я понятия не имею о проблеме «нарушения доступа».Вероятно, это будет зависеть от Windows.Я бы догадался, возможно, проблема с разрешениями или брандмауэром, но, прибегая к помощи «Нарушение доступа к сокету Windows», я вижу много случайных обсуждений.
Наконец, я не уверен, что ваши неблокирующие сокеты с while-цикламихорошая идея.Может быть, это можно сделать и так ... но мне всегда больше везло с блокировкой сокетов и потоков (опять же, потоки могут работать лучше в 'nix, чем в Windows.)
Примечание: если выработайте с неблокирующими сокетами, иногда вам приходится ловить / игнорировать как haxe.io.Error.Blocked
, так и haxe.io.Error.Custom(Blocked)
.Раздражение, но мех.Используйте это:
try {
Sys.print( oSocketDistant.input.readString(1) );
} catch ( e:haxe.io.Error ) {
switch e {
case haxe.io.Error.Blocked: // no problem
case haxe.io.Error.Custom(c) if (c==haxe.io.Error.Blocked): // no problem
default: throw e;
}
} catch ( e:haxe.io.Eof ) {
trace('Got Eof');
}
Более эффективно использовать потоки с блокирующими сокетами.Таким образом, нить просто спит, пока сокет ее не разбудит.Это именно то, что вам нужно, чтобы процессор не вращался во время цикла, постоянно проверяя наличие разблокированных сокетов.
Итак, я немного изменил ваш код.Мой пример использует основной поток для приема соединений, а затем передает сокет потоку чтения.Поток читателя печатает все полученное (как ваш пример), а затем завершается на Eof
.
import sys.net.Host;
import sys.net.Socket;
import sys.ssl.Socket as SocketSSL;
import sys.ssl.Certificate;
import sys.ssl.Key;
import cpp.vm.Mutex;
import cpp.vm.Thread;
class Main
{
static var _mutex:Mutex = new Mutex();
public static function main()
{
var _oSocketMaster = new SocketSSL();
var cert = Certificate.loadFile('my_chain.pem');
_oSocketMaster.setCA(cert);
_oSocketMaster.setCertificate(cert,
Key.loadFile('my_key.key'));
_oSocketMaster.setHostname('foo.example.com');
// e.g. for an application like an HTTPs server, the client
// doesn't need to provide a certificate. Otherwise we get:
// Error: SSL - No client certification received from the client, but required by the authentication mode
_oSocketMaster.verifyCert = false;
// Binding 0.0.0.0 means, listen on "any / all IP addresses on this host"
_oSocketMaster.bind( new Host( '0.0.0.0' ), 8000);
_oSocketMaster.listen( 9999 );
while(true) {
// Accepting socket
trace('waiting to accept...');
var oSocketDistant:SocketSSL = _oSocketMaster.accept();
if ( oSocketDistant != null ) {
trace( 'got connection from : ' + oSocketDistant.peer() );
oSocketDistant.handshake(); // This may not be necessary, if !verifyCert
// Spawn a reader thread for this connection:
var thrd = Thread.create(reader);
trace('sending socket...');
thrd.sendMessage(oSocketDistant);
trace('ok...');
}
}
}
static function reader()
{
var oSocketDistant:sys.net.Socket = cast Thread.readMessage(true);
trace('new reader thread...');
while(true) {
try {
Sys.print( oSocketDistant.input.readString(1) );
} catch ( e:haxe.io.Eof ) {
trace('Eof, reader thread exiting...');
return;
} catch ( e:Dynamic ) {
trace('Uncaught: ${ e }'); // throw e;
}
}
}
}
Итак, давайте посмотрим на это в действии!
Я скомпилировал и запустил вышеуказанный серверв одном терминале:
> haxe -main Main -debug -cpp out && ./out/Main-debug
...compiling info removed...
Main.hx:37: waiting to accept...
А потом я подключаюсь с другого терминала к клиенту, это утилита командной строки для тестирования ssl-соединений:
> openssl s_client -connect foo.example.com:8000
...lots of info about the cert...
SSL handshake has read 3374 bytes and written 370 bytes
Verification: OK
---
И она там висит, ждет васнабрать ввод.На стороне сервера мы видим:
Main.hx:38: got connection from : { host => Host, port => 57394 }
Main.hx:43: sending socket...
Main.hx:45: ok...
Main.hx:35: waiting to accept...
Main.hx:54: new reader thread...
Мы можем открыть много клиентов в отдельных терминалах, каждый из которых получает свой собственный поток чтения.Ввод сообщений в клиентские терминалы отображается в серверном терминале, поэтому потоки считывателя работают.
На клиенте CTRL + C для выхода, а на сервере мы видим:
Main.hx:61: Eof, reader thread exiting...
Все работает как положено!