문제

우리는 클라이언트와 서버를 작성하여 (내가 생각했던 것) 매우 간단한 네트워크 커뮤니케이션을 작성합니다. Mulitple 클라이언트는 서버에 연결하여 데이터를 다른 모든 클라이언트에게 다시 보내야합니다.

서버는 막힘에 있습니다 select 루프는 트래픽을 기다리고 있으며, 그렇다면 다른 클라이언트에게 데이터를 보냅니다. 이것은 잘 작동하는 것 같습니다.

문제는 클라이언트입니다. 읽기에 응답하여 때로는 글을 쓰고 싶어 할 것입니다.

그러나 사용하면 다음을 발견했습니다.

 rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);

내 코드는 읽을 새로운 데이터가있을 때까지 차단됩니다. 그러나 때때로 (다른 스레드에서 비동기 적으로) 네트워크 통신 스레드에 작성할 새로운 데이터가 있습니다. 그래서, 나는 내 선택이 주기적으로 깨어나고 다음과 같이 쓸 데이터가 있는지 확인하기를 원합니다.

if (select(....) != -1)
{
  if (FD_SET(sockfd, &master_list))
     // handle data or disconnect
  else
     // look for data to write and write() / send() those.
}

Select를 폴링 모드로 설정하려고 시도했습니다 (또는 엄청나게 짧은 시간 초과).

// master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);

그러나 고객은 들어오는 데이터를 얻지 못한다는 것을 알게되었습니다.

또한 소켓 FD를 비 블로킹으로 설정하려고 시도했습니다.

fcntl(sockfd, F_SETFL, O_NONBLOCK);

그러나 그것은 문제를 해결하지 못합니다.

  1. 내 클라이언트 인 경우 select() 없다 struct timeval, 데이터를 읽는 것이 효과가 있지만 쓰기 가능한 데이터를 찾을 수 있도록 차단되지는 않습니다.
  2. 내 클라이언트 인 경우 select() a timeval 설문 조사에 참여하려면 읽을 수있는 데이터가 있다는 신호를 보내지 않으며 내 앱은 네트워크 연결이 없다고 생각합니다 (다른 모든 기능 호출이 성공했다는 사실에도 불구하고).

내가 무엇을 잘못 할 수 있는지에 대한 포인터가 전혀 없습니까? 같은 소켓에서 읽기 쓰기를 할 수 없습니까 (사실이라고 믿을 수 없습니다).

(편집 : 정답과 클라이언트에서는 서버에서 기억했던 것은 두 번째 fd_set을 갖고 각 호출을 선택하기 전에 master_list를 복사하는 것입니다 () :

// declare and FD_ZERO read_fds:
// put sockfd in master_list

while (1)
{
   read_fds = master_list;
   select(...);

   if (FD_ISSET(read_fds))
     ....
   else
     // sleep or otherwise don't hog cpu resources
}

)

도움이 되었습니까?

해결책

당신이하는 줄을 제외하고는 모든 것이 잘 보입니다. if (FD_SET(sockfd, &master_list)). 매우 비슷한 코드 구조가 있고 사용했습니다. FD_ISSET. 목록이 설정되어 있는지 테스트하고 다시 설정하지 않도록 테스트해야합니다. 그 외에는 다른 것이 없습니다.

편집하다. 또한 타임 아웃에 대해 다음과 같은 것들이 있습니다.

timeval listening_timeout;
listening_timeout.tv_sec = timeout_in_seconds;
listening_timeout.tv_usec = 0;

아마도 당신이 그것을 0으로 설정하면 문제가있을 것입니다 (당신이하고있는 것처럼?)

edit2. 선택한 종료 후 읽기 세트를 지우지 않았을 때 그리고 다시 입력하기 전에 이상한 문제가 발생했음을 기억합니다. 나는 다음과 같은 일을해야했다 :

FD_ZERO(&sockfd);
FD_SET(sockfd, &rd);

내가 들어가기 전에 select. 그래도 이유를 기억할 수 없습니다.

다른 팁

네트워크 스레드와 선택 통화의 설명자에 추가 된 기본 스레드간에 읽기/쓰기 제출 스크립트를 작성하고 공유하는 것에 대한 트릭을 기억하는 것 같습니다. 이 FD에는 보낼 무언가가있을 때 메인 스레드에 의해 하나의 바이트가 작성되었습니다. WRITE는 SELECT CALL에서 네트워크 스레드를 깨우고 네트워크 스레드는 공유 버퍼에서 데이터를 가져 와서 네트워크에 씁니다.

약간 모호하고 코드가 부족한 경우 죄송합니다 ... 내 기억이 틀릴 수 있습니다. 따라서 다른 사람들이 당신을 더 안내해야 할 수도 있습니다.

코드에 아무런 문제가 없으므로 작동해야합니다. 작동하지 않으면 작업을 수행하는 한 가지 방법은 읽기 스레드와 글을 준비하는 스레드에서 사용할 파이프를 만들고 파이프의 판독 종료를 추가하는 것입니다. select 세트. 그런 다음 다른 스레드가 쓸 데이터를 작성하면 파이프에 무언가를 보내면 읽기 스레드가 깨어납니다. select, 그런 다음 글을 작성할 수 있습니다. 읽거나 쓸 데이터가 얼마나 자주 있는지에 따라 더 효율적일 수도 있습니다.

2 스레드는 한 번에 동일한 소켓으로 작동 할 수 있어야하므로 기본 스레드는 클라이언트에게 쓸 수 있어야하며 다른 하나는 수신 데이터를 기다리는 선택에서 잠을 자야합니다. 물론 이것은 두 스레드 모두 클라이언트 목록에 액세스 할 수 있다고 가정합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top