클라이언트 연결 실패 원인
연결 실패 클라이언트는 일반적으로 두 가지 오류가 있습니다: connection refuse 와 connection timeout
connection refuse(연결 거부)
일반적으로 다음과 같은 이유가 있습니다:
- 클라이언트 연결 포트가 잘못되었음
- 클라이언트 연결 도메인 또는 IP가 잘못되었음
- 클라이언트가 도메인을 사용하여 연결을 시도한 경우, 도메인이 잘못된 서버 IP를 가리킬 수 있음
- 서버가 CDN 등 가속 프록시를 사용하여 연결의 실제 IP가 예상된 IP와 일치하지 않음
- 서버가 시작되지 않았거나 포트가 리스닝 중이지 않음
- 네트워크 프록시 소프트웨어를 사용했음
- 서버 리스닝 IP와 접근 주소가 같은 주소 대역에 있지 않음. 예를 들어, 서버가 127.0.0.1를 리스닝 중이라면, 클라이언트는 127.0.0.1을 통해서만 연결할 수 있으며, 로컬 네트워크 IP 또는 외부 IP를 통해서는 연결할 수 없음. 리스닝 주소를 0.0.0.0으로 설정하는 것이 좋으며, 이렇게 하면 본인 컴퓨터, 내망, 외망 모두 연결할 수 있습니다.
connection timeout(연결 시간 초과)
일반적으로 다음과 같은 이유가 있습니다:
- 서버의 방화벽이 연결을 차단함. 방화벽을 일시적으로 꺼보는 것이 좋음
- 클라우드 서버인 경우, 보안 그룹이 연결 수립을 차단할 수 있으며, 관리 백엔드에서 해당 포트를 열어야 함
- 피관리 도구인 宝塔 등을 사용할 경우, 宝塔에서 해당 포트를 열어야 함
- 서버가 존재하지 않거나 시작되지 않았음
- 클라이언트가 도메인을 사용하여 연결을 시도한 경우, 도메인이 잘못된 서버 IP를 가리킬 수 있음
- 클라이언트가 접속하는 IP가 서버 내부 IP이며, 클라이언트와 서버가 같은 로컬 네트워크에 있지 않음
cannot assign requested address (요청된 주소를 할당할 수 없음)
클라이언트로서 각 연결을 시작할 때, 로컬의 임시 포트를 하나 사용해야 합니다. 하나의 서버는 기본적으로 사용할 수 있는 임시 포트가 대략 2-3만 개이며, 특정 서버에 대해 시작된 연결 수가 이 값을 초과하면 가용 포트를 할당할 수 없어 이 오류가 발생합니다.
/etc/sysctl.conf의 net.ipv4.ip_local_port_range를 변경하여 로컬 임시 포트 수를 늘릴 수 있으며, 예를 들어 10000 65535로 설정하면 (로컬 포트 범위를 10000에서 65535로 설정하여, 로컬 포트 수가 55535개로 증가) sysctl -p를 실행하여 적용됩니다.
또한 연결이 끊어진 후 연결이 TIME_WAIT 상태가 되어 해당 로컬 포트를 일정 시간 동안 계속 차지하게 되며, 짧은 시간 내에 대량(2-3만 개 초과)의 짧은 연결을 발생시키면 Cannot assign requested address 오류가 발생할 수 있습니다. 이러한 경우 내 kernel을 설정하여 TIME_WAIT을 빠르게 회수하도록 설정할 수 있습니다. 내부 조정을 참조하십시오.
주의
로컬 포트 수 제한은 클라이언트에만 해당되며, 서버는 로컬 포트 제한이 없으며 리소스가 충분하다면 서버가 유지할 수 있는 연결 수는 무한대로 볼 수 있습니다.
기타 오류
발생한 오류가 connection refuse 와 connection timeout가 아닌 경우, 일반적으로 다음과 같은 이유가 있습니다:
1. 클라이언트가 사용하는 통신 프로토콜이 서버와 일치하지 않음.
예를 들어, 서버가 http 통신 프로토콜인 경우, 클라이언트가 websocket 통신 프로토콜로 접근하면 연결할 수 없습니다. 클라이언트가 websocket 프로토콜로 연결할 경우, 서버도 websocket 프로토콜이어야 합니다. 서버가 http 프로토콜일 경우, 클라이언트는 http 프로토콜로 접근해야 합니다.
여기서의 원리는 만약 당신이 영국 사람과 소통하고자 한다면 영어를 사용해야 하고, 일본 사람과 소통하고자 한다면 일본어를 사용해야 한다는 것과 유사합니다. 여기서 언어는 통신 프로토콜과 유사하며, 양측(클라이언트와 서버)은 동일한 언어를 사용해야 소통할 수 있습니다. 그렇지 않으면 통신할 수 없습니다.
통신 프로토콜 불일치로 인한 일반적인 오류는 다음과 같습니다:
WebSocket connection to 'ws://xxx.com:xx/' failed: Error during WebSocket handshake: Unexpected response code: xxx
WebSocket connection to 'ws://xxx.com:xx/' failed: Error during WebSocket handshake: net::ERR_INVALID_HTTP_RESPONSE
해결 방법:
위의 두 오류에서 클라이언트가 사용하는 ws 연결은 websocket 프로토콜임을 알 수 있습니다. 서버 역시 websocket 프로토콜이어야 합니다. 서버 리스닝 부분 코드는 websocket 프로토콜을 지정해야 통신이 가능하며, 예를 들어 다음과 같이 설정할 수 있습니다.
gatewayWorker인 경우, 리스닝 부분 코드는 비슷하게
// websocket 프로토콜, 이렇게 클라이언트가 ws://...로 연결할 수 있습니다. xxxx는 포트값 변경 안 함
$gateway = new Gateway('websocket://0.0.0.0:xxxx');
Workerman인 경우는
// websocket 프로토콜, 이렇게 클라이언트가 ws://...로 연결할 수 있습니다. xxxx는 포트값 변경 안 함
$worker = new Worker('websocket://0.0.0.0:xxxx');