NIOWebSocketClient with arguments

I've downloaded NIOWebSocketClient and NIOWebSocketServer and copied each into Swift Packages on a Pi running 64bit BullsEye. They compile and run together perfectly on the same machine when using the default run arguments, but not when given a hostname and port. For example...

pi@rp64lite:~/NIOWebSocketClient $ swift run NIOWebSocketClient rp64lite.local 8888
[0/0] Build complete!
Establishing connection.
HTTP handler removed.
Swift/ErrorType.swift:200: Fatal error: Error raised at top level: NIOPosix.NIOConnectionError(host: "rp64lite.local", port: 8888, dnsAError: nil, dnsAAAAError: nil, connectionErrors: [NIOPosix.SingleConnectionFailure(target: [IPv4]rp64lite.local/, error: connection reset (error set): Connection refused (errno: 111))])
Current stack trace:
0                    0x0000007fb9d3c744 swift_reportError + 64
1                    0x0000007fb9dad1cc _swift_stdlib_reportFatalErrorInFile + 124
2                    0x0000007fb9aea718 _assertionFailure(_:_:file:line:flags:) + 296
3                    0x0000007fb9b4ae7c swift_errorInMain + 516
4    NIOWebSocketClient                 0x000000557d1fcfd0 <unavailable> + 2609104
5                          0x0000007fb95f5130 __libc_start_main + 232
6    NIOWebSocketClient                 0x000000557cfc6254 <unavailable> + 287316
Trace/breakpoint trap

I've tried using the ip6 address instead, but get a similar result. Please can someone tell me what I should be doing?

Ultimately, I want to connect to an external service that only requires a domain/path address (without a port number).

OK. I've found the answer is to get the server running in ip4 - like this...

pi@rp64lite:~/NIOWebSocketServer $ swift run NIOWebSocketServer 8888

But I'm still left wondering how to connect NIOWebSocketClient to the external server that doesn't expect me to send a port number.

(Paintext) HTTP runs over port 80 by default and WebSocket is usually upgraded from HTTP(S). So if you have a public server that speaks plaintext WebSocket (ws://...) then you can just put port 80 there. I will say that today, server (hopefully) don't speak plaintext HTTP anymore. They speak HTTPS and upgrade WebSocket from there (wss://..., note the extra s).

NIOWebSocketClient however is just a demo how to use NIO's WebSocket handlers. If you want to speak WebSocket over TLS (wss://...) as you should, then you'd need to combine that with a TLS implementation such as swift-nio-ssl or swift-nio-transport-services (which on Apple platforms lets Network.framework to the networking & TLS).

I will say that if you just want to use WebSocket, then NIO* is the wrong tool, it's way too low-level for what you're trying to do. I would recommend Vapor's websocket-kit if you want to use a WebSocket. It will do all the NIO & TLS bits for you.

Of course, if you're looking into NIOWebSocket for educational reasons or you want to create your own WebSocket library, then go ahead :slight_smile: .

1 Like

I'm going around in circles with NIO, so I'd like to try using web socket-kit as you suggest, but the README file has no content. Please tell me where It can see some practical examples of how to use it.

These are the docs for WebSocketKit.

CC @0xTim to maybe add a few standalone examples to WebSocketKit's.

Hi @johannesweiss This helps a bit, but I look forward to reading some working examples. Meanwhile, I have a couple of questions...

  1. Will this code work on linux without Vapor?

  2. Will it be possible to have a Server and a Client in the same linux application. ( Server on localhost, Client connecting to a remote server. )

I have the feeling you'll say "why not just use Vapor", but for me that will involve a lot more reading. Ideally, I'm hoping for a drop-in replacement for my half-baked NIO attempts.

We're well aware that the READMEs for all the Vapor *-Kit packages are severely lacking. We definitely plan on expanding these, usually around the time we pitch the package to the SSWG

I'm almost a year into developing a Swift / SwiftNIO / SwiftUI system using an iMac and 2 remote 64bit Debian RPi Servers to control and monitor a Digital Amateur TeleVision transmitter, receiver, power supplies and cooling, which will communicate with the wide band transponder on a geostationary satellite.

This is not your average 99 cent IOS App. I've spent thousands of my money on this project and its almost ready to share with the community, but the networking side has been a pain since day two - when I migrated from Python to Swift.

I'm pleased to hear your intent to add examples, but please can you give me some idea on how much longer I'll be left in the dark?



The tests provide up to date examples of how to set it all up and use it

To @johannesweiss and @0xTim
FYI I've installed Vapor on a spare RPi and I can confirm that it works on Debian Bullseye 64bit Lite and Swift 5.6. I even managed to get TLS working even though the documented method didn't work for me. Maybe this is the way I should go, so I'll play with this for a while and pester you later.

My app requires a continuous 'stream' of json status data - without being asked by a request. But, it will need to act on a number of specific requests.

Searching the Internet for help is futile, because its swamped with outdated IOS articles. Not many seem to be interested in real time machine control.

As far as I can see, the tests don't test the client.

Most of the tests spin up a server then use the client to connect to it, e.g.