2013-05-27 3 views
2

클라이언트가 서버에 연결하려고하면 클라이언트와 서버가 모두 로컬 호스트 인 경우 자체 연결이 발생할 수 있습니다 (원본 포트와 대상 포트가 동일하게 발생 함). 하지만 내 문제는 클라이언트가 그 포트를 듣지 않고 어떻게 자기 연결이 가능할 수 있는가하는 것입니다.Linux/Unix 소켓 자체 연결

+0

는 듣고 사용하는 서버 (일반적으로) ... – vvy

+0

@vvy 내 질문을 더 자세히 읽어야한다고 생각합니다. –

답변

0

우리가 할 수있는 간단한 재현 다음 파이썬 프로그램

import socket 
for i in range(65536): 
    try: 
    s = socket.create_connection(('127.0.0.1', 50000)) 
    print 'connected to {0}'.format(s.getpeername()) 
    except Exception as e: 
    pass 

우리가 같은 호스트에 어떤 소켓을 연결하려고이 현상. 클라이언트를 특정 포트에 연결하지 않으면 운영 체제에서 ephemeral port을 제공합니다. 그것이 당신이 연결하고 싶은 사람이 되었다면. 자체 연결을 유발합니다. 연결할 포트가 /proc/sys/net/ipv4/ip_local_port_range

2

localhost의 서버와 클라이언트는 동일한 포트를 사용하지 않습니다. 소스 포트가 연결된 TCP 연결로

, 서버

하고 목적지 포트가 클라이언트

B.

이며, 소스 포트 B 및 목적지 포트 A.

A는

이다 서버에서 bind()에 의해 설정되며 모든 임상 진료소에 알려져 있습니다. B는 일반적으로 임상 진료 팀의 커널에 의해 할당되며 서버의 accept()가 반환 될 때 서버에 알려져 있습니다.

세부

: TCP에서

는 서버의 포트를 바인드()에 의해 우리가 모두 또는 어느 포트 번호, IP 주소를 지정할 수있는 설정하지만, TCP 서버가 있도록하는 것이 드문입니다 커널은 일시적인 포트를 선택한다. 서버는 포트와 IP 주소를 listen()한다.

클라이언트는 소켓 주소 구조에 서버의 IP 주소와 포트 번호가 포함되어야하는 connect()를 사용합니다. 커널은 필요한 경우 임시 포트와 소스 IP 주소를 모두 선택합니다. 어쨌든 서버가 사용하는 포트가 될 수 없습니다.

즉, 동일한 컴퓨터에있는 서버와 임상 시험용 컴퓨터의 포트는 동일하지 않습니다.

Proto Recv-Q Send-Q Local Address   Foreign Address    State  
tcp  0  0 localhost:41742   localhost:9877   ESTABLISHED 
tcp  0  0 localhost:9877   localhost:41742   ESTABLISHED 

prots을 분명히 다르다 : 터미널에서 netstat -t를 입력, 당신은 얻을 것이다, 로컬 호스트에서 실행하는 간단한 C/S 프로그램은 예를를 들어

.

클라이언트가 클라이언트의 동일한 포트를 사용하도록 강제하면 bind()에 의해 로컬에서 사용중인 서버가 bind()가 오류 -1을 반환합니다.

+1

내 문제를 오해 한 것 같습니다. 내가 말한 것은 자기 연애 문제 다.실제로 이런 상황에서는 서버가 없습니다. 프로그램 자체가 실제로 연결됩니다. –

+1

@SkyShaw 이것 좀 봐 : http://lkml.indiana.edu/hypermail/linux/kernel/9909.3/0510.html, 사실보고 싶은가요? – vvy

+0

당신이 거기서 발견 한 매우 흥미로운 토론, @vvy,하지만 그것은 결론없이 사라져가는 것처럼 보입니다. 우발적 인자가 연결이 작성되고 병합되는 것을 방지하기위한 패치였습니까? –

2

같은 현상이 발생한 후에 찾았습니다. 내가 찾은 가장 좋은 설명은 Everything About Nothing: TCP Client Self Connect입니다.

이러한 자기 연결을 감지하는 getsockname을 통해 사용자에게 할당 된 포트()을 요청하고 원격 포트에 비교할 수 있습니다

sockaddr_in addr_client; 
socklet_t len = sizeof(saddr_in); 

if(getsockname(sock_client, (struct sockaddr *)&addr_client, &len)) 
    { /* error */ } 
if(len != sizeof(saddr_in))) 
    { /* error */ } 

if(addr_client.sin_port == addr_server.sin_port && 
    addr_client.sin_addr.s_addr == addr_server.addr.sin_addr.s_addr) 
    { /* self-connection detected! */ }