Flutter远程连接管理插件telnet的使用
Flutter远程连接管理插件telnet的使用
使用 Dart 语言实现的 Telnet 客户端。
功能特点
- 支持选项协商、子选项协商和文本消息传输
- 支持 TLS 安全传输
- 消息事件侦听
- 枚举了所有的 Telnet 命令码和选项码
使用方法
创建一个 Telnet 连接任务:
// 常规方式
final task = TelnetClient.startConnect(
host: host,
port: port,
timeout: timeout,
onError: onError,
onDone: onDone,
onEvent: onEvent,
);
// 使用 TLS 安全传输
final task = TelnetClient.startSecureConnect(
host: host,
port: port,
timeout: timeout,
onError: onError,
onDone: onDone,
onEvent: onEvent,
securityContext: securityContext,
supportedProtocols: supportedProtocols,
onBadCertificate: onBadCertificate,
);
等待连接任务结束,然后获取 TelnetClient
实例对象:
// 同步方式
await task.waitDone();
final client = task.client;
final connected = client != null;
// 异步方式
task.onDone = (client) {
final connected = client != null;
}
取消连接任务:
task.cancel();
关闭 Telnet 连接:
client.terminate();
侦听并处理消息事件:
final task = TelnetClient.startConnect(
host: host,
port: port,
onEvent: (client, event) {
final eventType = event.type;
final eventMsg = event.msg;
if (eventType == TLMsgEventType.write) {
print("这是一个写事件,数据由客户端发往服务端。");
} else if (eventType == TLMsgEventType.read) {
print("这是一个读事件,数据由服务端发往客户端。");
}
if (eventMsg is TLOptMsg) {
// 选项协商
print("IAC ${eventMsg.cmd.code} ${eventMsg.opt.code}");
} else if (eventMsg is TLSubMsg) {
// 子选项协商
print("IAC SB ${eventMsg.opt.code} ${eventMsg.arg.join(' ')} IAC SE");
} else if (eventMsg is TLTextMsg) {
// 文本消息
print(eventMsg.text);
}
},
);
完整使用方法示例
以下是一个完整的示例代码,展示了如何使用 telnet
插件进行远程连接管理。
import 'package:telnet/telnet.dart';
const host = "127.0.0.1";
const port = 23;
const username = "root";
const password = "admin";
const echoEnabled = true;
void main() async {
// 创建一个 Telnet 连接任务。
final task = TelnetClient.startConnect(
host: host,
port: port,
onEvent: _onEvent,
onError: _onError,
onDone: _onDone,
);
// 取消连接任务。
// task.cancel();
// 等待连接任务完成。
await task.waitDone();
// 获取 `TelnetClient` 实例。如果连接失败,则为 `null`。
final client = task.client;
if (client == null) {
print("无法连接到 $host:$port");
} else {
print("成功连接到 $host:$port");
}
await Future.delayed(const Duration(seconds: 10));
// 关闭 Telnet 连接。
await client?.terminate();
}
var _hasLogin = false;
final _willReplyMap = <TLOpt, List<TLMsg>>{
TLOpt.echo: [echoEnabled
? TLOptMsg(TLCmd.doIt, TLOpt.echo) // [IAC DO ECHO]
: TLOptMsg(TLCmd.doNot, TLOpt.echo)], // [IAC DON'T ECHO]
TLOpt.suppress: [TLOptMsg(TLCmd.doIt, TLOpt.suppress)], // [IAC DO SUPPRESS_GO_AHEAD]
TLOpt.logout: [],
};
final _doReplyMap = <TLOpt, List<TLMsg>>{
TLOpt.echo: [echoEnabled
? TLOptMsg(TLCmd.will, TLOpt.echo) // [IAC WILL ECHO]
: TLOptMsg(TLCmd.wont, TLOpt.echo)], // [IAC WONT ECHO]
TLOpt.logout: [],
TLOpt.tmlType: [
TLOptMsg(TLCmd.will, TLOpt.tmlType), // [IAC WILL TERMINAL_TYPE]
TLSubMsg(TLOpt.tmlType, [0x00, 0x41, 0x4E, 0x53, 0x49]), // [IAC SB TERMINAL_TYPE IS ANSI IAC SE]
],
TLOpt.windowSize: [
TLOptMsg(TLCmd.will, TLOpt.windowSize), // [IAC WILL WINDOW_SIZE]
TLSubMsg(TLOpt.windowSize, [0x00, 0x5A, 0x00, 0x18]), // [IAC SB WINDOW_SIZE 90 24 IAC SE]
],
};
void _onEvent(TelnetClient? client, TLMsgEvent event) {
if (event.type == TLMsgEventType.write) {
print("[WRITE] ${event.msg}");
} else if (event.type == TLMsgEventType.read) {
print("[READ] ${event.msg}");
if (event.msg is TLOptMsg) {
final cmd = (event.msg as TLOptMsg).cmd; // Telnet Negotiation Command.
final opt = (event.msg as TLOptMsg).opt; // Telnet Negotiation Option.
if (cmd == TLCmd.wont) {
// Write [IAC DO opt].
client?.write(TLOptMsg(TLCmd.doNot, opt));
} else if (cmd == TLCmd.doNot) {
// Write [IAC WON'T opt].
client?.write(TLOptMsg(TLCmd.wont, opt));
} else if (cmd == TLCmd.will) {
if (_willReplyMap.containsKey(opt)) {
// Reply the option.
for (var msg in _willReplyMap[opt]!) {
client?.write(msg);
}
} else {
// Write [IAC DON'T opt].
client?.write(TLOptMsg(TLCmd.doNot, opt));
}
} else if (cmd == TLCmd.doIt) {
// Reply the option.
if (_doReplyMap.containsKey(opt)) {
for (var msg in _doReplyMap[opt]!) {
client?.write(msg);
}
} else {
// Write [IAC WON'T opt].
client?.write(TLOptMsg(TLCmd.wont, opt));
}
}
} else if (!_hasLogin && event.msg is TLTextMsg) {
final text = (event.msg as TLTextMsg).text.toLowerCase();
if (text.contains("welcome")) {
_hasLogin = true;
print("[INFO] 登录成功!");
} else if (text.contains("login:") || text.contains("username:")) {
// Write [username].
client!.write(TLTextMsg("$username\r\n"));
} else if (text.contains("password:")) {
// Write [password].
client!.write(TLTextMsg("$password\r\n"));
}
}
}
}
void _onError(TelnetClient? client, dynamic error) {
print("[ERROR] $error");
}
void _onDone(TelnetClient? client) {
print("[DONE]");
}
更多关于Flutter远程连接管理插件telnet的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter远程连接管理插件telnet的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter应用中实现远程连接管理,特别是使用Telnet协议,通常需要借助一些原生平台(如Android和iOS)的代码来实现,因为Flutter本身并不直接支持Telnet协议。不过,可以通过插件或者平台通道来调用原生代码完成这项任务。
以下是一个简化的例子,展示如何在Flutter中通过平台通道调用原生代码来实现Telnet连接。这个例子将分为Flutter前端代码和原生后端代码两部分。
Flutter前端代码
首先,在Flutter项目中创建一个新的插件(或者使用现有的插件)来定义平台通道。这里我们假设已经创建了一个名为telnet_plugin
的插件。
// telnet_plugin.dart
import 'package:flutter/services.dart';
class TelnetPlugin {
static const MethodChannel _channel = const MethodChannel('com.example.telnet_plugin');
static Future<void> connectToTelnet(String host, int port, String username, String password) async {
try {
await _channel.invokeMethod('connectToTelnet', {
'host': host,
'port': port,
'username': username,
'password': password,
});
} on PlatformException catch (e) {
print("Failed to connect to Telnet: '${e.message}'.");
}
}
}
然后,在你的Flutter应用中使用这个插件:
// main.dart
import 'package:flutter/material.dart';
import './telnet_plugin.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Telnet Example'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
TelnetPlugin.connectToTelnet('your.telnet.server', 23, 'username', 'password');
},
child: Text('Connect to Telnet'),
),
),
),
);
}
}
原生后端代码
Android部分
在android/app/src/main/java/com/example/yourappname/
目录下创建一个新的Kotlin/Java类来处理Telnet连接。
// TelnetHandler.kt
package com.example.yourappname
import android.content.Context
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import java.io.*
import java.net.Socket
class TelnetHandler(private val context: Context, private val channel: MethodChannel) : MethodCallHandler, FlutterPlugin, ActivityAware {
private var activityBinding: ActivityPluginBinding? = null
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "connectToTelnet") {
val arguments = call.arguments as? Map<*, *> ?: return
val host = arguments["host"] as? String ?: return
val port = (arguments["port"] as? Number)?.toInt() ?: return
val username = arguments["username"] as? String ?: return
val password = arguments["password"] as? String ?: return
connectToTelnet(host, port, username, password, result)
} else {
result.notImplemented()
}
}
private fun connectToTelnet(host: String, port: Int, username: String, password: String, result: Result) {
try {
val socket = Socket(host, port)
val output = PrintWriter(BufferedWriter(OutputStreamWriter(socket.getOutputStream())), true)
val input = BufferedReader(InputStreamReader(socket.getInputStream()))
output.println("$username$password") // 简单的登录示例,实际需要根据协议调整
// 读取响应
var line: String?
while (input.readLine().also { line = it } != null) {
println(line)
}
socket.close()
result.success(null)
} catch (e: Exception) {
result.error("TELNET_ERROR", e.message, null)
}
}
override fun onAttachedToEngine(binding: FlutterPluginBinding) {
channel.setMethodCallHandler(this)
}
override fun onDetachedFromEngine(binding: FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activityBinding = binding
}
override fun onDetachedFromActivityForConfigChanges() {
activityBinding = null
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activityBinding = binding
}
override fun onDetachedFromActivity() {
activityBinding = null
}
}
然后,在MainActivity.kt
中注册这个插件:
// MainActivity.kt
package com.example.yourappname
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.telnet_plugin")
val context = applicationContext
TelnetHandler(context, channel)
}
}
iOS部分
对于iOS,你需要使用Swift或Objective-C来实现类似的逻辑。由于篇幅限制,这里只提供一个简单的Swift框架:
// TelnetHandler.swift
import Flutter
public class TelnetHandler: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "com.example.telnet_plugin", binaryMessenger: registrar.messenger())
let instance = TelnetHandler()
channel.setMethodCallHandler(onMethodCall: instance.handle(_:result:))
}
private func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
guard call.method == "connectToTelnet" else {
result(.notImplemented())
return
}
guard let arguments = call.arguments as? [String: Any],
let host = arguments["host"] as? String,
let port = arguments["port"] as? Int,
let username = arguments["username"] as? String,
let password = arguments["password"] as? String else {
result(.error(withCode: "INVALID_ARGUMENTS", message: "Invalid arguments", details: nil))
return
}
connectToTelnet(host: host, port: port, username: username, password: password, result: result)
}
private func connectToTelnet(host: String, port: Int, username: String, password: String, result: @escaping FlutterResult) {
var client: NWConnection?
client = NWConnection(host: NWEndpoint.Host(host), port: NWEndpoint.Port(port: UInt16(port)), using: .tcp)
client?.start(queue: .main) { [weak self] (error) in
guard let self = self else { return }
if let error = error {
result(.error(withCode: "CONNECTION_ERROR", message: error.localizedDescription, details: nil))
return
}
let output = "\(username)\(password)\n" // 简单的登录示例,实际需要根据协议调整
client?.send(content: Data(output.utf8), completion: { (error) in
if let error = error {
result(.error(withCode: "SEND_ERROR", message: error.localizedDescription, details: nil))
return
}
// 读取响应
client?.receive(minimumIncompleteLength: 1, maximumLength: 1024, completion: { (data, context, isComplete, error) in
if let error = error {
result(.error(withCode: "RECEIVE_ERROR", message: error.localizedDescription, details: nil))
return
}