2012-11-21 3 views
3

소켓에 쓰는 동안 내 TCP/IP 클라이언트가 멈 춥니 다. 이는 서버가 close() (또는 shutdown()) 호출로 허용 된 연결을 제대로 닫은 경우에도 발생합니다. 난 항상이 사건에 대한 ECONNRESET 오류와 함께 반환되어야한다고 생각했습니다.닫힌 TCP/IP 연결에 쓰기가 응답하지 않는다

동기 출력에서 ​​전화 끊기를 어떻게 방지합니까? 또는 오히려 무엇이 잘못되어 오류가 write()에 의해보고되지 않습니까?

write() 대신 send()을 사용해야합니까? 아니면 교환 가능합니까?

두 개의 스레드가있는 별도의 응용 프로그램에서 네트워킹을 테스트하고 있습니다. 주 스레드는 서버 스레드를 시작하고 연결을 허용하고 즉시 닫습니다. 그런 다음 주 스레드는 수신 대기 포트에 연결하여 클라이언트 동작을 모방합니다.

메인 쓰레드 코드 :

sockaddr_in serv_addr; 
bzero((char *) &serv_addr, sizeof(serv_addr)); 
serv_addr.sin_family = AF_INET; 
serv_addr.sin_addr.s_addr = INADDR_ANY; 
serv_addr.sin_port = htons(port); 
int s = socket(AF_INET, SOCK_STREAM, 0); 
if (bind(s, (sockaddr*)(&serv_addr), sizeof(serv_addr)) < 0) { 
    close(s); 
    throw runtime_error(strerror(errno)); 
} 
listen(s,1); 
start_thread(s); // posix thread accepting a connection on s is started here 
//Code below imitates TCP/IP client 
struct hostent *hp; 
struct sockaddr_in addr; 
if((hp = gethostbyname(host.c_str())) == NULL){ 
    throw HErrno(); 
} 
bcopy(hp->h_addr, &addr.sin_addr, hp->h_length); 
addr.sin_port = htons(port); 
addr.sin_family = AF_INET; 
int _socket = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 
if (_socket < 0) { 
    throw Errno(); 
} 
assert(ENOTCONN==107); 
assert(_socket>=0); 
if(::connect(_socket, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1){ 
    throw Errno(); 
} 

while(true) { 
    const char a[] = "pattern"; 
    if (write(_socket, a, 7)<0) // Writes 30000 times, then hangs 
    break; 
} 

서버 스레드 코드 :

int connection = accept(s); 
close(connection); 

편집 : 내 프로그래밍 오류로 감소 문제. 그것은 제대로 스레드를 받아들이 기 시작하지 못한 것 같습니다.

+0

클라이언트가 연결을 시도 할 때 서버가 이미 수신을 시작했는지 어떻게 확인합니까? – fayyazkl

+0

@fayyazkl, 스레드 시작을 수락하기 전에 수신 대기가 있습니다. 수락 호출이 성공하고 읽을 수있는 fd를 반환합니다. – Basilevs

+0

@fayyazkl 그게 문제라면 그는 write()를 멈추지 않고 연결 만 할 것이다. – EJP

답변

1

각 TCP 연결에는 수신되었지만 응용 프로그램으로 배달되지 않은 데이터를 저장하기위한 수신 버퍼가 있습니다. 서버에서 read()를하지 않으면 데이터가 수신 버퍼에 누적되고 한 번에이 수신 버퍼가 가득 차서 TCP가 Window = 0 메시지를 보냅니다.

서버 스레드 코드는 다음과 같아야합니다

char a[10]; 
int connection = accept(s); 
while(true) 
    if (read(connection , a, 7)<=0) 
     break; 
close(connection); 
+0

클라이언트가 영원히 열린 연결에서 결코 쓰지 않으면 영원히 중단됩니다. 어떻게 읽지 않고 연결을 종료합니까? 그리고'close()'가이 연결 인스턴스의 모든 버퍼를 비우지 않는 이유는 무엇입니까? – Basilevs

+0

1) 클라이언트가 close()를 수행하면 ok입니다. read()가 0을 반환하고 루프가 닫힙니다. 2) 물론 close()가 있지만 모든 쓰기가 끝나면 close()를 수행합니다. 3) close()는 수신 측의 모든 버퍼를 해제하지만 송신 측을 제어 할 수는 없습니다. – banuj

+0

1) 분명히 실제 애플리케이션 서버에서는 클라이언트가 어떤 일을하는지 전혀 알 수 없습니다. 따라서 클라이언트의 행동에 의존하는 것은 의미가 없습니다. 2) 동일 - 클라이언트가 서버가 아닌 쓰기를 수행합니다. 모든 기록이 언제 완료되는지는 정확하게 예측할 수 없습니다. 3) 그러면 클라이언트 측의 TCP/IP가 계속해서 ack를 수신하고 오류를보고하지 않는 이유는 무엇입니까? – Basilevs

0

당신은 아마 SIG_IGN로 설정하는 대신 SIGPIPE에 대한 핸들러를 설정 했습니까?

관련 문제