Skip to content

Instantly share code, notes, and snippets.

@sphinxlikee
Last active July 6, 2023 08:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sphinxlikee/3cbfa47817a5187c7b67905028674041 to your computer and use it in GitHub Desktop.
Save sphinxlikee/3cbfa47817a5187c7b67905028674041 to your computer and use it in GitHub Desktop.
TCP Client
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter-TCP/IP Client'),
);
}
}
final serverAddressProvider = Provider<String>((ref) => '127.0.0.1');
final serverPortProvider = Provider<int>((ref) => 64123);
final tcpClientProvider = ChangeNotifierProvider<TCPClient>(
(ref) => TCPClient(
serverAddress: ref.read(serverAddressProvider),
serverPort: ref.read(serverPortProvider),
),
);
final streamProvider = StreamProvider.autoDispose(
(ref) async* {
await for (final value in ref.watch(tcpClientProvider).streamController.stream) {
yield value;
}
},
);
class MyHomePage extends ConsumerWidget {
final String title;
MyHomePage({this.title});
@override
Widget build(BuildContext context, ScopedReader watch) {
return Scaffold(
appBar: AppBar(
title: Text('$title'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
DataSendButton(),
SizedBox(height: 10),
// ReceivedDataWithProvider(),
ReceivedData(),
SizedBox(height: 20),
DataSendIndicator(),
DataReceiveIndicator(),
ConnectionIndicator(),
],
),
floatingActionButton: ConnectButton(),
);
}
}
class ReceivedData extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final receivedData = watch(tcpClientProvider).receivedData;
return Text('Received data: $receivedData');
}
}
class ReceivedDataWithProvider extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
AsyncValue receivedData = watch(streamProvider);
return receivedData.when(
data: (data) => Text('Received data: $data'),
loading: () => const CircularProgressIndicator(),
error: (err, stack) => Text('error'),
);
}
}
class ConnectButton extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final isConnected = watch(tcpClientProvider).connectionState;
return FloatingActionButton(
onPressed: isConnected ? null : () async => await context.read(tcpClientProvider).createConnection(),
tooltip: isConnected ? 'Connected' : 'Connect',
child: isConnected ? Icon(Icons.connect_without_contact_outlined) : Icon(Icons.touch_app_sharp),
);
}
}
class ConnectionIndicator extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final isConnected = watch(tcpClientProvider).connectionState;
return ListTile(
leading: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isConnected ? Colors.green : Colors.red,
),
),
title: Text('Connection Status '),
subtitle: isConnected ? Text('Connected') : Text('Disconnected'),
);
}
}
class DataSendButton extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final isConnected = watch(tcpClientProvider).connectionState;
return ElevatedButton(
onPressed: !isConnected
? null
: () {
context.read(tcpClientProvider).writeToStream('DateTime: ${DateTime.now()}');
},
child: Text('Send DateTime.now()'),
);
}
}
class DataSendIndicator extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final isDataSent = watch(tcpClientProvider).dataSentState;
return ListTile(
leading: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isDataSent ? Colors.green : Colors.red,
),
),
title: Text('Data'),
subtitle: isDataSent ? Text('Sent') : Text('Not sent'),
);
}
}
class DataReceiveIndicator extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final isDataReceived = watch(tcpClientProvider).dataReceivedState;
return ListTile(
leading: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isDataReceived ? Colors.green : Colors.red,
),
),
title: Text('Data'),
subtitle: isDataReceived ? Text('Received') : Text('Not received'),
);
}
}
class TCPClient with ChangeNotifier {
final String serverAddress;
final int serverPort;
String receivedData;
bool _isConnected, _dataReceived, _dataSent;
Socket _socket;
final streamController;
TCPClient({
@required this.serverAddress,
@required this.serverPort,
}) : _isConnected = false,
_dataReceived = false,
_dataSent = false,
receivedData = 'empty',
streamController = StreamController();
get connectionState => _isConnected;
get dataReceivedState => _dataReceived;
get dataSentState => _dataSent;
void _changeConnectionState() {
if (!_isConnected)
_isConnected = true;
else
_isConnected = false;
notifyListeners();
}
void _changeDataReceivedState() {
_dataReceived = true;
notifyListeners();
}
void _changeDataSentState() {
_dataSent = true;
notifyListeners();
}
void _streamDone() async {
_dataReceived = false;
_dataSent = false;
receivedData = 'empty';
await _socket.flush();
await _socket.close();
notifyListeners();
}
void _getData(var data) {
receivedData = data;
notifyListeners();
}
void writeToStream(String data) {
_socket.write('$data\r\n');
if (!dataSentState) {
_changeDataSentState();
}
}
// for the StreamProvider version
// Future<void> createConnection() async {
// try {
// _socket = await Socket.connect(serverAddress, serverPort);
// streamController.sink.add(_socket.listen((event) => String.fromCharCodes(event)));
// _changeConnectionState();
// } catch (e) {
// print('connection has an error and socket is null.');
// print(e);
// return;
// }
// }
Future<void> createConnection() async {
try {
_socket = await Socket.connect(serverAddress, serverPort);
_changeConnectionState();
} catch (e) {
print('connection has an error and socket is null.');
print(e);
return;
}
listenSocket();
}
void listenSocket() {
_socket.listen(
(event) {
_getData(String.fromCharCodes(event));
print('received: $receivedData');
if (!_dataReceived) {
_changeDataReceivedState();
}
},
)
..onDone(
() {
_changeConnectionState();
_streamDone();
print('socket is closed');
},
)
..onError(
(error, stackTrace) {
print('$error');
},
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment