如何使用Haxe SSL Socket?
How to use Haxe SSL Socket?
我正在尝试设置一个 https 服务器,但我找不到任何关于如何使用 Haxe 的示例 sys.ssl.Socket
,文档也不太适合我。
到目前为止,我得到了以下抛出 'Access violation'.
的代码
var _aSocketDistant = new List<Socket>();
var _oSocketMaster = new SocketSSL();
_oSocketMaster.setCA(Certificate.loadFile('ssl/homeplanet.pem'));
_oSocketMaster.setCertificate(
Certificate.loadFile('ssl/homeplanet.pem'),
Key.loadFile('ssl/homeplanet.key', false, 'homeplanet')
);
_oSocketMaster.setHostname('localhost');
_oSocketMaster.bind( new Host( 'localhost' ), 8000);
_oSocketMaster.setBlocking( false );
_oSocketMaster.listen( 9999 );
while(true) {
// Accepting socket
var oSocketDistant = _oSocketMaster.accept();
if ( oSocketDistant != null ) {
trace( 'opening : ' + oSocketDistant.peer() );
oSocketDistant.setBlocking( false );
_aSocketDistant.add( oSocketDistant );
}
// Trying to read from each socket
for ( oSocketDistant in _aSocketDistant ) {
try {
Sys.print( oSocketDistant.input.readString(1) );
} catch ( e :Dynamic ) {
if ( e != Error.Blocked )
throw e;
}
}
}
这给了我以下结果:
Uncaught exception: Access violation
Called from sys.ssl.Socket.accept(D:\HaxeToolkit4\haxe\std/hl/_std/sys/ssl/Socket.hx:203)
Called from $Main.main(Main.hx:39)
Called from fun7(?:1)
使用 this tutorial.
生成的 key/certificate 个文件
我是否正确使用了插座?
好的,我决定自己测试 Haxe SSL 套接字。由于有很多注意事项,这可能不是您问题的答案,但也许一些花絮会有所帮助。从 "something that works" 开始总比没有好!
首先,我在 Linux。我发现套接字(和线程)在 Windows 上可能表现出与在 Linux / OSX.
上不同的行为和问题
其次,我首先尝试使用有效的主机名。我从未在 localhost
上使用过 SSL,并希望删除所有未知数。所以我碰巧有一个有效的 cert/key 我正在使用。在下面的代码中,它被称为 foo.example.com
。您可以在 letsencrypt.org.
获得您拥有的域的免费证书
第三,我在 Haxe std 库中 运行 进入 an issue。为了解决这个问题,我只是更改了 haxe/std/cpp/_std/sys/ssl/Key.hx
:
中的第 17 行
var str = data.toString(); // cpp.Lib.stringReference(data);
第四,我对"access violation"的问题一无所知。那很可能是 Windows-specific。我猜可能是权限或防火墙问题,但谷歌搜索 "Windows socket access violation",我看到很多 运行dom 讨论。
最后,我不确定您使用 while-loops 的 non-blocking 套接字是否是个好主意。也许它可以那样做......但我在阻塞套接字和线程方面总是比较幸运(同样,线程在'nix上的表现可能比Windows更好。)
Note: If you do work with non-blocking sockets, sometimes you have to catch / ignore both haxe.io.Error.Blocked
and haxe.io.Error.Custom(Blocked)
. An irritation, but meh. Use this:
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');
}
使用带阻塞套接字的线程效率更高。这样,线程就可以简单地休眠,直到套接字将其唤醒。这就是您想要的,因此 CPU 不会在 while 循环中旋转,无休止地检查未阻塞的套接字。
所以我稍微修改了您的代码。我的示例使用主线程接受连接,然后将套接字传递给 reader 线程。 reader 线程打印收到的所有内容(如您的示例),然后在 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...
我们可以在不同的终端中打开许多客户端,它们每个都有自己的 reader 线程。在客户端中键入消息会显示在服务器终端中,因此 reader 线程正在工作。
在客户端,CTRL+C退出,在服务端我们看到:
Main.hx:61: Eof, reader thread exiting...
一切正常!
我正在尝试设置一个 https 服务器,但我找不到任何关于如何使用 Haxe 的示例 sys.ssl.Socket
,文档也不太适合我。
到目前为止,我得到了以下抛出 'Access violation'.
的代码var _aSocketDistant = new List<Socket>();
var _oSocketMaster = new SocketSSL();
_oSocketMaster.setCA(Certificate.loadFile('ssl/homeplanet.pem'));
_oSocketMaster.setCertificate(
Certificate.loadFile('ssl/homeplanet.pem'),
Key.loadFile('ssl/homeplanet.key', false, 'homeplanet')
);
_oSocketMaster.setHostname('localhost');
_oSocketMaster.bind( new Host( 'localhost' ), 8000);
_oSocketMaster.setBlocking( false );
_oSocketMaster.listen( 9999 );
while(true) {
// Accepting socket
var oSocketDistant = _oSocketMaster.accept();
if ( oSocketDistant != null ) {
trace( 'opening : ' + oSocketDistant.peer() );
oSocketDistant.setBlocking( false );
_aSocketDistant.add( oSocketDistant );
}
// Trying to read from each socket
for ( oSocketDistant in _aSocketDistant ) {
try {
Sys.print( oSocketDistant.input.readString(1) );
} catch ( e :Dynamic ) {
if ( e != Error.Blocked )
throw e;
}
}
}
这给了我以下结果:
Uncaught exception: Access violation
Called from sys.ssl.Socket.accept(D:\HaxeToolkit4\haxe\std/hl/_std/sys/ssl/Socket.hx:203)
Called from $Main.main(Main.hx:39)
Called from fun7(?:1)
使用 this tutorial.
生成的 key/certificate 个文件我是否正确使用了插座?
好的,我决定自己测试 Haxe SSL 套接字。由于有很多注意事项,这可能不是您问题的答案,但也许一些花絮会有所帮助。从 "something that works" 开始总比没有好!
首先,我在 Linux。我发现套接字(和线程)在 Windows 上可能表现出与在 Linux / OSX.
上不同的行为和问题其次,我首先尝试使用有效的主机名。我从未在 localhost
上使用过 SSL,并希望删除所有未知数。所以我碰巧有一个有效的 cert/key 我正在使用。在下面的代码中,它被称为 foo.example.com
。您可以在 letsencrypt.org.
第三,我在 Haxe std 库中 运行 进入 an issue。为了解决这个问题,我只是更改了 haxe/std/cpp/_std/sys/ssl/Key.hx
:
var str = data.toString(); // cpp.Lib.stringReference(data);
第四,我对"access violation"的问题一无所知。那很可能是 Windows-specific。我猜可能是权限或防火墙问题,但谷歌搜索 "Windows socket access violation",我看到很多 运行dom 讨论。
最后,我不确定您使用 while-loops 的 non-blocking 套接字是否是个好主意。也许它可以那样做......但我在阻塞套接字和线程方面总是比较幸运(同样,线程在'nix上的表现可能比Windows更好。)
Note: If you do work with non-blocking sockets, sometimes you have to catch / ignore both
haxe.io.Error.Blocked
andhaxe.io.Error.Custom(Blocked)
. An irritation, but meh. Use this: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'); }
使用带阻塞套接字的线程效率更高。这样,线程就可以简单地休眠,直到套接字将其唤醒。这就是您想要的,因此 CPU 不会在 while 循环中旋转,无休止地检查未阻塞的套接字。
所以我稍微修改了您的代码。我的示例使用主线程接受连接,然后将套接字传递给 reader 线程。 reader 线程打印收到的所有内容(如您的示例),然后在 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...
我们可以在不同的终端中打开许多客户端,它们每个都有自己的 reader 线程。在客户端中键入消息会显示在服务器终端中,因此 reader 线程正在工作。
在客户端,CTRL+C退出,在服务端我们看到:
Main.hx:61: Eof, reader thread exiting...
一切正常!