NIO入门

本文开发语言基于Swift 代码参考EchoServer

目录

  • 环境

  • 开始

  • NIO

  • 测试

  • 概念

    • Blocking-I/O

    • Non-Blocking-I/O

环境

MacOS安装Xcode即可 所以以下环境搭建基于Ubuntu1604

sudo apt install -y clang libicu-dev git
git clone https://github.com/kylef/swiftenv.git ~/.swiftenv

echo 'export SWIFTENV_ROOT="$HOME/.swiftenv"' >> ~/.zshrc

echo 'export PATH="$SWIFTENV_ROOT/bin:$PATH"' >> ~/.zshrc

echo 'eval "$(swiftenv init -)"' >> ~/.zshrc

source ~/.zshrc
swiftenv install 4.0.3

swift --version

关于swiftenv 更多参考swiftenv

开始

mkdir EchoServer

# cd EchoServer
swift package init --type executable
swift build

.build/debug/EchoServer
Hello, world!

NIO

vim Package.swift
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "EchoServer",
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(url: "https://github.com/apple/swift-nio.git", from: "1.1.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "EchoServer",
            dependencies: ["NIO"]),
    ]
)
swift package resolve
vim Sources/EchoServer/main.swift
import NIO

// EchoHandler
private final class EchoHandler: ChannelInboundHandler {
    public typealias InboundIn = ByteBuffer
    public typealias OutboundOut = ByteBuffer

    private var count: Int = 0

    public func channelRegistered(ctx: ChannelHandlerContext) {
        print("channel registered:", ctx.remoteAddress ?? "unknown")
    }

    public func channelUnregistered(ctx: ChannelHandlerContext) {
        print("channel unregistered")
    }

    public func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
        let buffer = self.unwrapInboundIn(data)
        print("read:", buffer.getString(at: 0, length: buffer.readableBytes)!)
        ctx.write(data, promise: nil)
    }

    public func channelReadComplete(ctx: ChannelHandlerContext) {
        print("read complete")
        ctx.flush()
    }

    public func errorCaught(ctx: ChannelHandlerContext, error: Error) {
        print("error: ", error)
        ctx.close(promise: nil)
    }
}

// Bootstrap
let group = MultiThreadedEventLoopGroup(numThreads: System.coreCount)
let bootstrap = ServerBootstrap(group: group)
        .serverChannelOption(ChannelOptions.backlog, value: 256)
        .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
        .childChannelInitializer { channel in
            channel.pipeline.add(handler: BackPressureHandler()).then { v in
                channel.pipeline.add(handler: EchoHandler())
            }
        }
        .childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
        .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
        .childChannelOption(ChannelOptions.maxMessagesPerRead, value: 16)
        .childChannelOption(ChannelOptions.recvAllocator, value: AdaptiveRecvByteBufferAllocator())
defer {
    try! group.syncShutdownGracefully()
}

let channel = try bootstrap.bind(host: "::1", port: 9999).wait()
print("Server started and listening on \(channel.localAddress!)")
try channel.closeFuture.wait()
print("Server terminated")

测试

  • Server
swift build && .build/debug/EchoServer
Compile Swift Module 'EchoServer' (1 sources)
Server started and listening on [IPv6]::1:9999
  • Client
telnet localhost 9999

MacOS安装telnet方法: brew install telnet

Trying ::1...
Connected to localhost.
Escape character is '^]'.
  • Close
^]
telnet> close

概念

mkdir Node

# cd Node
echo "file content" >> ./file

Blocking I/O

vim bio.js
console.log('start')
const data = require('fs').readFileSync('./file');
console.log('read:', data.toString());
console.log('end');
node bio.js
start
read: file content

end

Non-Blocking I/O

vim nio.js
console.log('start')
require('fs').readFile('./file', (err, data) => {
    if (err) throw err;
    console.log(data.toString());
});
console.log('end');
node nio.js
start
end
read: file content

参考

  • swift-nio

  • 苹果公司开源的Swift版Netty:SwiftNIO

  • Developing a basic Swift Echo Server using Swift-NIO

  • Overview of Blocking vs Non-Blocking

  • 非同步程式設計和 non-blocking IO

你可能感兴趣的:(NIO入门)