I haven't been using gRPC until today.
Since I've taken time to try to simulate this error I'll post here my answer but all my intel has been lead by @ishann answer that I've upvoted and that should be the accepted one.
I've just tried dart hello world example.
I've the server running on my machine and the client as a Flutter application.
When I don't run the server I get the error
gRPC Error (14, Error connecting: SocketException:

But as soon as the server goes up, all start working as expected, but then I've realized that I was recreating the channel every time, so that's not the OP scenario.
That's my fist Flutter code:
void _foo() async {
final channel = new ClientChannel('192.168.xxx.xxx',
port: 50051,
options: const ChannelOptions(
credentials: const ChannelCredentials.insecure()));
final stub = new GreeterClient(channel);
final name = 'world';
var _waitHelloMessage = true;
while (_waitHelloMessage) {
try {
final response = await stub.sayHello(new HelloRequest()..name = name);
print('Greeter client received: ${response.message}');
_waitHelloMessage = false;
} catch (e) {
print('Caught error: $e');
sleep(Duration(seconds: 1));
}
}
print('exiting');
await channel.shutdown();
}
Same behaviour if I put device in airplain mode and than switch back to normal wifi/lte connection.
With this other playground project instead I've reproduced either
Caught error: gRPC Error (14, Error making call: Bad state: The http/2 connection is no longer active and can therefore not be used to make new streams.)
From which you cannot come up without recreating the channel, and
Caught error: gRPC Error (14, Error connecting: SocketException: OS Error: Connection refused, errno = 111, address = 192.168.1.58, port = 38120)
(for example shut down the server) from which instead you can get up again without recreating the channel.
The former error code it's not so easy to get because it seems that the channel throttle between wifi and lte connection.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app_test_grpc/grpc/generated/helloworld.pbgrpc.dart';
import 'package:grpc/grpc.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
ClientChannel _channel;
@override
void dispose() {
_shutdown();
super.dispose();
}
void _shutdown() async {
if (null != _channel) {
print('shutting down...');
await _channel.shutdown();
print('shut down');
_channel = null;
} else {
print ('connect first');
}
}
void _connect() {
print('connecting...');
_channel = new ClientChannel('192.168.xxx.xxx',
port: 50051,
options: const ChannelOptions(
credentials: const ChannelCredentials.insecure()));
print('connected');
}
void _sayHello() async {
if (_channel != null) {
final stub = new GreeterClient(_channel);
final name = 'world';
try {
final response = await stub.sayHello(new HelloRequest()..name = name);
print('Greeter client received: ${response.message}');
} catch (e) {
print('Caught error: $e');
//sleep(Duration(seconds: 2));
}
//print('exiting');
//await channel.shutdown();
} else {
print('connect first!');
}
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: Padding(
padding: const EdgeInsets.only(left: 36.0),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: _connect,
tooltip: 'Increment',
child: Icon(Icons.wifi),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: _sayHello,
tooltip: 'Increment',
child: Icon(Icons.send),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: _shutdown,
tooltip: 'Increment',
child: Icon(Icons.close),
),
),
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

That's my flutter doctor -v if could be of any help:
$ flutter doctor -v
[✓] Flutter (Channel beta, v1.0.0, on Mac OS X 10.14.1 18B75, locale en-IT)
• Flutter version 1.0.0 at /Users/shadowsheep/flutter/flutter
• Framework revision 5391447fae (6 weeks ago), 2018-11-29 19:41:26 -0800
• Engine revision 7375a0f414
• Dart version 2.1.0 (build 2.1.0-dev.9.4 f9ebf21297)
[✓] Android toolchain - develop for Android devices (Android SDK 28.0.3)
• Android SDK at /Users/shadowsheep/Library/Android/sdk
• Android NDK location not configured (optional; useful for native profiling support)
• Platform android-28, build-tools 28.0.3
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
• All Android licenses accepted.
[✓] iOS toolchain - develop for iOS devices (Xcode 10.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 10.1, Build version 10B61
• ios-deploy 1.9.4
• CocoaPods version 1.5.3
[✓] Android Studio (version 3.3)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin version 31.3.3
• Dart plugin version 182.5124
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
[✓] VS Code (version 1.30.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 2.21.1
[✓] Connected device (1 available)
[...]
• No issues found!