Http: SocketException: Reading from a closed socket

Created on 29 Jan 2019  路  8Comments  路  Source: dart-lang/http

I am making a simple http request, and when I do, the program either throws the exception SocketException: Reading from a closed socket, or it just quietly hangs and never returns. Here is what my code looks like:

void main() async {
  const url = 'https://example.com';
  final client = http.Client();

  var i = 0;
  var count = 10;

  while (i < count) {
     final options = {...};
     final response = await client.post(url, body: options);
     // deal with response
     ++count
  }
  client.close();
}

And as I mentioned above, this hangs or throws:

Unhandled exception:
SocketException: Reading from a closed socket
#0      _RawSecureSocket.read (dart:io/secure_socket.dart:694:7)
#1      _Socket._onData (dart:io/runtime/binsocket_patch.dart:1720:27)
#2      _RootZone.runUnaryGuarded (dart:async/zone.dart:1314:10)
#3      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:336:11)
#4      _BufferingStreamSubscription._add (dart:async/stream_impl.dart:263:7)
#5      _SyncStreamController._sendData (dart:async/stream_controller.dart:763:19)
#6      _StreamController._add (dart:async/stream_controller.dart:639:7)
#7      _StreamController.add (dart:async/stream_controller.dart:585:5)
#8      _RawSecureSocket._sendReadEvent (dart:io/secure_socket.dart:1005:19)
#9      Timer._createTimer.<anonymous closure> (dart:async/runtime/libtimer_patch.dart:21:15)
#10     _Timer._runTimers (dart:isolate/runtime/libtimer_impl.dart:382:19)
#11     _Timer._handleMessage (dart:isolate/runtime/libtimer_impl.dart:416:5)
#12     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)

Oddly, this only seems to happen for certain URLs. Some URLs run perfectly every time, and then some cause it to hang. If it matters, I'm making POST requests to a online form.

Most helpful comment

I receive this error intermittently when creating multiple WebSocketChannel. I have a factory function like

// ...
channelFactory: () => IOWebSocketChannel.connect(
    Config.instance.apiWsHostUrl,
    headers: {
    'Authorization': 'Bearer $token',
    },
),
// ...

Which is then opened and closed with functions like

  bool open() {
    if (isActive) {
      return false;
    }

    _monitor.start();
    _channel$.add(consumer.channelFactory())
    _state = ConnectionState.Open;

    return true;
  }

  bool close() {
    if (!this.isActive) {
      return false;
    }

    _monitor.stop();
    _channel$.value.sink.close(status.goingAway);
    _channel$.add(null);
    _state = ConnectionState.Closed;

    return true;
  }

And after calling open() and close() in succession we get the SocketException: Reading from a closed socket error from within the WebSocket.connect call

flutter: SocketException: Reading from a closed socket
flutter: dart:_http                                                         WebSocket.connect
flutter: package:web_socket_channel/io.dart 58:19                           new IOWebSocketChannel.connect
 .... from that factory function call and more ....

This only happens on the second open call: the state goes like open() -> close() -> open()

All 8 comments

Am I making requests too fast? The requests are in a while loop and I process the results almost immediately so it ends up making calls one after the other very fast.

Does the library discourage/prevent this? Should I add delays?

Might be related to this dropped call issue: https://github.com/dart-lang/sdk/issues/34477

I don't know what URLs you are trying to post to but maybe some of them have anti spam methods on them, which instead of showing a soft error just closes the connection to you.

final response = await http.post(...) Only succeeds if it got a response from the remote. So error handling with response.statusCode only works if you received a response from the server see codes.

The way to handle this is a try {}catch(){} block

try {
    final  response = await http.post(...);
    /// Your code, handle soft errors here (statusCodes)
 catch(error) {
    /// Handle 'hard' errors here, broken connections, connection refused, etc etc
}

There is also another way, but I haven't managed to get this working and that is by using the Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});

To the (edit:) flutter developers, I think that the Cookbook: Fetch data from the internet should explain error handling better, and maybe abstract the exception handling inside the package itself.

Okay I managed to make the other way work, which is prettier than a try catch block imo.

final post = client.post(url, body: options);
await get.then((response){
    if (response.statusCode == 200){
            // Everything okay
    }else{
        // soft error, see status codes
      }
}, onError: (err){
    // Exception error, see err.toString();
});

By the way you can skip the final client = http.Client(); and go straight to final post = http.post(url, body: options);

Yeah weird still hanging! I have the call wrapped in a try/catch already and it never throws an error, it just hangs and waits. I guess its just something about the URLs I'm trying to hit. However, the same POST requests succeed in Postman and in a Google Cloud function, which is what makes me feel like it is Dart specific.

Also, isn't using a Client better if you are making many calls to the same server and want to keep the connection open?

I receive this error intermittently when creating multiple WebSocketChannel. I have a factory function like

// ...
channelFactory: () => IOWebSocketChannel.connect(
    Config.instance.apiWsHostUrl,
    headers: {
    'Authorization': 'Bearer $token',
    },
),
// ...

Which is then opened and closed with functions like

  bool open() {
    if (isActive) {
      return false;
    }

    _monitor.start();
    _channel$.add(consumer.channelFactory())
    _state = ConnectionState.Open;

    return true;
  }

  bool close() {
    if (!this.isActive) {
      return false;
    }

    _monitor.stop();
    _channel$.value.sink.close(status.goingAway);
    _channel$.add(null);
    _state = ConnectionState.Closed;

    return true;
  }

And after calling open() and close() in succession we get the SocketException: Reading from a closed socket error from within the WebSocket.connect call

flutter: SocketException: Reading from a closed socket
flutter: dart:_http                                                         WebSocket.connect
flutter: package:web_socket_channel/io.dart 58:19                           new IOWebSocketChannel.connect
 .... from that factory function call and more ....

This only happens on the second open call: the state goes like open() -> close() -> open()

@shrugs, Even we have a similar issue with our app. Have you got any lead or solution or workaround?

@kssujithcj can't remember making any progress on this, sorry

Was this page helpful?
0 / 5 - 0 ratings