UNIX 네트워크 프로그래밍 - 비차단 connect: 시간 획득 클라이언트 프로그램

4473 단어
#include	"unp.h"

int
connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec)
{
	int				flags, n, error;
	socklen_t		len;
	fd_set			rset, wset;
	struct timeval	tval;

	flags = fcntl(sockfd, F_GETFL, 0);
	fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

	error = 0;
	if ( (n = connect(sockfd, saptr, salen)) < 0)// , , -1,errno EINPROGRESS
		if (errno != EINPROGRESS)
			return(-1);

	/* Do whatever we want while the connect is taking place. */

	if (n == 0)// , 
		goto done;	/* connect completed immediately */

	FD_ZERO(&rset);
	FD_SET(sockfd, &rset);
	wset = rset;
	tval.tv_sec = nsec;
	tval.tv_usec = 0;

	if ( (n = select(sockfd+1, &rset, &wset, NULL,
					 nsec ? &tval : NULL)) == 0) {
		close(sockfd);		/* timeout */
		errno = ETIMEDOUT;
		return(-1);
	}

	if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
		len = sizeof(error);
		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)//error 0, ; , 
			return(-1);			/* Solaris pending error */
	} else
		err_quit("select error: sockfd not set");

done:
	fcntl(sockfd, F_SETFL, flags);	/* restore file status flags */

	if (error) {
		close(sockfd);		/* just in case */
		errno = error;
		return(-1);
	}
	return(0);
}

참고: 플러그인 연결 오류로 인해 플러그인을 읽을 수 있는 코드 설명이 있습니다. >에 있는connect_timeout 함수.
플러그인을 비저지 11-12로 설정하고 fcntl를 호출하여 플러그인을 비저지 14-17로 설정하여 비저지connect를 시작합니다.예상 오류는 EINPROGRESS로 연결 구축이 시작되었지만 완료되지 않았음을 나타냅니다.connect가 되돌려주는 다른 오류는 이 함수의 호출자에게 되돌려줍니다.
다른 처리에 있어서 연결 구축 19 이로써 우리는 연결 구축이 완성되기를 기다리는 동안 우리가 하고 싶은 일을 할 수 있습니다.
연결이 지금 21-22인지 확인하십시오. 만약 막히지 않으면connect가 0으로 되돌아옵니다.그럼 연결이 됐습니다.우리는 서버가 고객이 있는 호스트에 있을 때 이런 상황이 발생할 수 있다고 이미 말했다.
select 24-31을 호출하여 select 대기 플러그인을 읽거나 쓸 수 있도록 합니다.이 설명자를 열어 sockfd에 대응하는 위치를 집중하고rset을 wset으로 복사합니다.묘사 집합을 복사하는 값은 구조적 값일 수 있습니다. 왜냐하면 묘사 집합은 일반적으로 구조적 표현으로 사용되기 때문입니다.timeval 구조를 초기화하고 select를 호출합니다.만약 호출자가 네 번째 파라미터를 0 (기본 시간 초과 사용 표시) 으로 지정한다면, 우리는 select의 마지막 파라미터를 빈 바늘로 지정해야 합니다. 값이 0인 timeval 구조가 아니라.주의: 플러그인 연결 오류가 발생하면 플러그인을 읽을 수 있고 쓸 수 있습니다.이 때 select도 성공으로 돌아갑니다.
처리 시간 초과 32-35 만약 select가 0으로 되돌아온다면, 시간 초과가 발생하면, 우리는 ETIMEOUT 오류를 호출자에게 되돌려줍니다.우리는 이미 시작된 세 차례의 악수가 계속되는 것을 방지하기 위해 플러그인을 닫아야 한다.
읽을 수 있거나 쓸 수 있는 조건 37-42를 검사합니다. 설명자가 읽을 수 있거나 쓸 수 있는 것으로 바뀌면 getsockopt를 호출하여 소켓의 처리 대기 오류를 가져옵니다. (SO_ERROR 소켓 옵션 사용)연결이 성공적으로 설정되면 error는 0이 됩니다.연결 설정에 오류가 발생하면 이 값은 연결 오류에 대응하는 errno 값(예를 들어 ECONNREFUSED, ETIMEDOUT 등)입니다.플러그인 연결 오류가 발생하면 플러그인을 읽을 수 있고 쓸 수 있습니다.연결이 성공하면 플러그인이 쓸 수 있게 됩니다.이곳에서 우리는 첫 번째 이식성 문제에 부딪힐 것이다.만약 오류가 발생하면 getsockopt는 Berkeley에서 이루어진 것으로 우리의 변수error에서 처리할 오류를 되돌려줍니다. getsockopt 자체는 0을 되돌려줍니다.그러나 Solaris는 getsockopt를 -1로 되돌려주고 errno 변수를 처리할 오류로 설정합니다.그러나 우리의 프로그램은 이 두 가지 상황을 동시에 처리할 수 있다.
비차단 상태를 끄고 45-52 복구 플러그인의 파일 상태 표시를 되돌려줍니다.getsockopt에서 되돌아오는 error 변수가 0이 아니라면, 이 값을 errno에 저장하고, 함수 자체가 -1을 되돌려줍니다.
플러그인의 각종 실현과 비저지connect는 이식성 문제를 가져올 수 있다.우선, select를 호출하기 전에 연결이 설정되어 있고 대단에서 온 데이터가 도착할 수 있습니다.이런 상황에서 플러그인에 오류가 발생하지 않아도 플러그인은 읽을 수도 있고 쓸 수도 있다. 이것은 연결 구축이 실패한 상황에서 플러그인의 읽기와 쓰기 조건과 같다.위 코드에서 getsockopt를 호출하고 플러그인에 처리할 오류가 있는지 확인합니다.
그 다음에 플러그인의 쓰기 가능 조건을 가정할 수 없을 때 select가 플러그인 조작 성공 조건을 되돌려주는 유일한 방법은 다음 이식성 문제는 연결 구축의 성공 여부를 어떻게 판단하는 것이다.다음은 getsockopt를 대체하는 여러 가지 해결 방법입니다. (여기서 getsockopt를 사용해도 됩니다. SO_ERROR 플러그인 옵션을 사용하면 error를 0으로 보고 연결 구축을 표시합니다. 0이 아니라 연결 플러그인 오류를 표시합니다.)
  • getsockopt 대신 getpeername을 호출합니다.getpeername이 ENOTCNN 오류로 되돌아오면 연결 설정이 실패했습니다. 이어서 SO_ERROR에서 getsockopt를 호출하여 소켓에서 처리할 오류를 얻었습니다..
  • 값이 0인 길이 매개 변수로read를 호출합니다.read가 실패하면,connect가 실패했습니다.read가 되돌아오는 errno는 연결 실패의 원인을 제시합니다.연결이 성공하면read는 0을 되돌려야 합니다.
  • 연결을 한 번 더 호출합니다.그것은 실패해야 합니다. 만약 오류가 EISCONN이라면 플러그인은 이미 연결되었습니다. 즉, 첫 번째 연결이 성공했다는 것입니다..

  • 불행하게도 비저지connect는 네트워크 프로그래밍에서 가장 이식하기 어려운 부분이다.이 기술을 사용하려면 이식성 문제, 특히 비교적 오래된 실현에 대처해야 한다.이식성 문제를 피하는 비교적 간단한 기술은 모든 연결을 위한 처리 라인을 만드는 것이다.
    끊긴 연결
    앞의 블로그에는 > 에 대한 설명이 나와 있습니다.
    정상적인 차단식 플러그인에 대해, 만약 그 위에 있는connect 호출이 TCP에서 세 번의 악수가 끝나기 전에 중단된다면, (예를 들어 어떤 신호를 포착했다면) 무슨 일이 일어날까요?인터럽트된connect 호출이 커널에서 자동으로 재부팅되지 않으면 EINTR로 돌아갑니다.연결이 완료되지 않은 연결이 계속 끝날 때까지 연결을 다시 호출할 수 없습니다.이렇게 하면 EADDRINUSE로 돌아가는 오류가 발생합니다.
    이 절에서connect를 막는 것처럼select만 호출할 수 있습니다.연결이 성공했을 때 select는 플러그인을 쓸 수 있는 조건을 되돌려주고, 연결이 실패했을 때 select는 플러그인을 읽을 수 있고 쓸 수 있는 조건을 되돌려줍니다.

    좋은 웹페이지 즐겨찾기