I'm needing to write a simple socket relay and I've bootstrapped two sockets that successfully receive connections. However, when I attempt to write what has been read on the one socket to the outgoing socket no bytes are sent.
Perhaps I'm overcomplicating this with two sockets, but I need to ensure only one sockets input gets sent to all the other sockets clients and the listening socket clients don't send anything to the input socket.
I'm bootstrapping the sockets similarly:
final class CloudRelay {
let listeningPort: UInt
let group = MultiThreadedEventLoopGroup(numberOfThreads: max(1,System.coreCount-1))
let channel: Channel?
init(port: UInt) {
listeningPort = port
// Set up the server using a Bootstrap
let bootstrap = ServerBootstrap(group: group)
// Define backlog and enable SO_REUSEADDR options atethe server level
.serverChannelOption(ChannelOptions.backlog, value: 256)
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
// Handler Pipeline: handlers that are processing events from accepted Channels
// To demonstrate that we can have several reusable handlers we start with a Swift-NIO default
// handler that limits the speed at which we read from the client if we cannot keep up with the
// processing through EchoHandler.
// This is to protect the server from overload.
.childChannelInitializer { channel in
channel.pipeline.add(handler: BackPressureHandler()).then { v in
channel.pipeline.add(handler: CloudRelayHandler())
}
}
// Enable common socket options at the channel level (TCP_NODELAY and SO_REUSEADDR).
// These options are applied to accepted Channels
.childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
.childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
// Message grouping
.childChannelOption(ChannelOptions.maxMessagesPerRead, value: 16)
// Let Swift-NIO adjust the buffer size, based on actual trafic.
.childChannelOption(ChannelOptions.recvAllocator, value: AdaptiveRecvByteBufferAllocator())
// Bind the port and run the server
do {
channel = try bootstrap.bind(host: "0.0.0.0", port: Int(listeningPort)).wait()
print("Server started and listening on \(channel!.localAddress!)")
}
catch {
print("Server failed to start")
channel = nil
}
}
deinit {
try? group.syncShutdownGracefully()
}
}
In the input socket ChannelInboundHandler I respond to the channelRead as such, attempting to write to the other socket's channel:
// Invoked when data are received from the client
public func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
ctx.write(data, promise: nil) // echo
var buf = unwrapInboundIn(data)
let s = buf.readString(length: buf.readableBytes)
print("Read: \(s ?? "")")
cloudRelay?.channel?.writeAndFlush(data, promise: nil)
}
Am I setting up the 2nd socket incorrectly to get it to write what is sent from the first socket? I do have a InboundHandler on both sockets to accept the connections but neither really aren't transforming messages, just forwarding; its OutboundHandler write() handler is never being called.
Should I even have two sockets here but still limit just the one known input connection to writing to the other clients?
TIA