Dart/Flutter

[Dart/Flutter] HttpException: Connection closed while receiving data 문제 해결

Flask를 사용하여 로컬 서버를 만들어, 이를 공용 IP로 접속하여 데이터를 받으려고 하는데, 

HttpException: Connection closed while receiving data 라는 에러가 발생하였습니다.

이걸 해결하기 위해 했던 여러가지 방법을 소개해드리겠습니다! 제가 시도했던 방법들을 순서대로 나열할 것이기 때문에, 어느 순서에서 되게 될지는 모르겠습니다

 

1. 안드로이드 스튜디오 에뮬레이터 proxy 설정

이걸로 해결했다는 분들 많으시던데, 저는 이걸로 안되더라구요. 실패!

 

 

2. 안드로이드 스튜디오 에뮬레이터(플러터) 보안 설정

// xml/network-security-config.xml
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">example.com</domain>
    </domain-config>
</network-security-config>
// AndroidManifest.xml
<application
    android:networkSecurityConfig="@xml/network_security_config"
    ... >
    ...
</application>

 android/app/src/main/res에 xml 폴더를 추가하시고, network-security-config.xml 파일을 만들어주세요.

그리고 첫번째 부분의 코드를 적고 저장한 뒤, AndroidManifest.xml에 두번째 부분의 코드를 적고 저장해주세요. 

(개발중에만 사용하고, 실제 배포시에는 빼주시는게 좋아요)

 

 

3. Dio 사용 함수 변경

Future<void> play(String url) async {
    try {
      Map<String, String> header = {'Content-Type': "audio/wav'", "Connection": "keep-alive"};
      Directory tempDir = await getTemporaryDirectory();
      String tempPath = '${tempDir.path}/temp_audio.wav';
      Response response = await Dio(
        BaseOptions(
          connectTimeout: Duration(seconds: 60),
          receiveTimeout: Duration(seconds: 60),
          sendTimeout: Duration(seconds: 60),
          headers: header,
          persistentConnection: true,
          method: 'GET',
          responseType: ResponseType.bytes
        ),
      ).download(url, tempPath,
          options: Options(
            headers: header,
            persistentConnection: false,
          ), onReceiveProgress: (received, total) {
        if (total != -1) {
          print('Downloading: ${(received / total * 100).toStringAsFixed(0)}%');
        }
      });
      print('Download Completed: ${response.statusCode}');

      } else {
        print('File does not exist at path: $tempPath');
      }
    } on DioError catch (e) {
      print('Dio error: $e');
      if (e.response != null) {
        print('Dio error response data: ${e.response?.data}');
        print('Dio error response headers: ${e.response?.headers}');
        print('Dio error response statusCode: ${e.response?.statusCode}');
      } else {
        print('Dio error request: ${e.requestOptions}');
        print('Dio error message: ${e.message}');
      }
    } catch (e) {
      print('Error starting player: $e');
    }
  }

connectionTimeout, receiveTimeout, sendTimeout 등을 바꿨는데, 사실 이거는 굳이 안건드리셔도 될것 같습니다! 이거 바꿨어도 어차피 안됬었거든요… 그래도 적어봤습니다.

 

여기까지가 클라이언트 측에서 수정한 내용들이고, 이후 수정은 서버에서 하였습니다!

 

4. Flask 서버 환경 개선

flask에 gunicorn을 추가하면 여러가지 설정이 가능합니다.
먼저 gunicorn을 설치해주세요.
pip install gunicorn

기존의 flask 실행할 때 python app.py 라면, gunicorn을 사용하여 실행할 때는 아래와 같이 실행하면 됩니다.

gunicorn app.app

하지만 우리는 추가 설정을 하기 위해 gunicorn을 설치한 것이니, 추가 설정을 해보도록 하겠습니다.

실행 파일과 같은 위치에 ‘service_config.py’를 만들어주세요.

# service_config.py

# 서버 바인딩 설정
bind = '0.0.0.0:8000'

# 워커 설정
workers = 4  # 워커 프로세스 수
worker_class = 'gevent'  # 워커 클래스 (gevent 사용 예시)
worker_connections = 1000  # gevent 워커당 최대 연결 수

# 타임아웃 설정
timeout = 30  # 타임아웃 설정 (초)
keepalive = 2  # 유지 시간 설정 (초)

# 로그 설정
accesslog = '/path/to/access.log'  # 접근 로그 파일 경로
errorlog = '/path/to/error.log'  # 에러 로그 파일 경로
loglevel = 'info'  # 로그 레벨 (debug, info, warning, error, critical)

# 보안 설정
limit_request_line = 4094  # 요청 라인 제한 (바이트)
limit_request_fields = 100  # 요청 헤더 필드 수 제한
limit_request_field_size = 8190  # 요청 헤더 필드 크기 제한 (바이트)

# 기타 설정
preload_app = False  # 앱 미리 로드 여부
max_requests = 0  # 워커가 재시작되기 전에 처리할 최대 요청 수
max_requests_jitter = 0  # max_requests에 대한 지터 값 (랜덤하게 추가되는 최대 값)
graceful_timeout = 30  # 우아한 종료를 위한 타임아웃 (초)

본인이 원하는 설정대로 설정하시면 됩니다! 저는 아래와 같이 설정했어요.

# service_config.py

bind = '0.0.0.0:8000'
workers = 4
keepalive = 30
timeout = 30
workers_class = 'gthread'
thread = 10
worker_connections = 10000
timeout = 30

그리고 아래와 같이 실행하시면 됩니다.

gunicorn -c service_config.py app:app

이렇게 4가지 방법을 HttpException: Connection closed while receiving data 문제를 해결했습니다.

아마도 서버의 대역폭 또는 설정이 미흡하여 저런 문제가 생겼던것 같아요.

저와 비슷한 문제를 겪으신 분에게 도움이 되셨으면 좋겠습니다.

읽어주셔서 감사합니다!

Info-Geon

Recent Posts

[Flask/WSL] WSL2 서버 외부 접속 시, 접속 안되는 문제 해결

WSL2로 서버를 실행 시켰을 때, 접속이 안될때가 있습니다. 분명 외부IP를 적어서 접속을 했는데도 안된다면, 들어와서…

2개월 ago

[Dart/Flutter] Future, Stream의 차이와 async, then의 차이

Dart를 이용하여 코딩을 하다 보면, Future, Stream 등을 사용할 때가 있습니다. 또한 받을 때는 async를…

3개월 ago

커피는 어떻게 우리의 잠을 깨울까? 커피의 효과와 부작용

커피는 어떻게 우리의 잠을 깨우고 각성시킬까요? 또한 이로 인한 부작용은 무엇일까요? 알고 마시면 더 좋은…

3개월 ago

WWDC 24 핵심 요약: 애플 AI 핵심 업데이트 및 Siri의 혁신

애플의 연례 개발자 회의인 WWDC 2023에서 애플은 많은 사람들의 기대를 모았던 AI 기술, 특히 Siri의…

3개월 ago

[Dart/Flutter] bool operator == (Object other)이 뭘까요? (객체 동등성 비교)

bool operator == (Object other) 과 같은 코드가 한번씩 보입니다. 과연 이는 무엇을 뜻하는 코드일까요?…

3개월 ago

뇌 과학으로 밝혀낸 다이어트 성공 습관(a.k.a 습관과 의지력의 진실)

전체 글의 세줄 요약은 아래에 있습니다! 다이어트에 성공했다가 다시 체중이 증가하는 경우는 매우 흔합니다. 저도 다이어트에…

3개월 ago