반성: select 에 대한 경험

오늘 제출 했 으 니 몇 가지 절 차 를 바 꿔 야 합 니까?서버 리 트 윗 채 팅 프로그램 으로 처음으로 다른 사람의 예 를 바탕 으로 직접 만 들 었 다.나중에 내 가 사용 할 때 막 히 는 것 을 발 견 했 는데, 당시 에 고려 한 문제 가 너무 많 았 다.가방 하 나 를 여러 번 나 눠 서 받 았 거나 한 번 에 받 았 거나 서로 독립 적 이 고 완전한 가방 몇 개 를 포함한다.
가장 중요 한 문 제 는 사용 료 가 막 힌 io 이후 select 에 대한 FDISSET 는 오 류 를 이해 했다.나 는 직감 을 믿 었 다.하나의 구조 체 를 사 용 했 는데 그 안에 recvbuffer [1024] 와 이미 받 아들 인 데이터 의 크기 를 각각 올 렸 다.또한 데 이 터 를 받 아들 일 때 for (;;) 를 사용 하여 다음 과 같은 변태 함수 가 나 타 났 다.
void recvFromClient(int m, struct targetPack *ss, int *testint, char *content)
{
	int recvsize;
	int totalsize;
	char *ptr;
	totalsize = 1024;
	ptr = conns[m].totalBuffer;
			
	memset(ss,0,sizeof(struct targetPack));
	//memset(conns[m].totalBuffer,0,1024);

	for(;;)
	{
		recvsize = 0;
		recvsize = recv(conns[m].clientfd, ptr, totalsize-conns[m].edSize, MSG_DONTWAIT);
		if(recvsize > 0)
		{	
			ptr += recvsize;
			conns[m].edSize += recvsize;
			printf("Received %d bytes
",recvsize); } else if(recvsize < 0) { if(errno == EAGAIN) { errno=0; printf("errno == EAGAIN"); break; } else { perror("recv"); exit(EXIT_FAILURE); } } else if(recvsize = 0) { printf("client has discontent
"); break; } if(conns[m].edSize >= border_size) { memcpy(ss, conns[m].totalBuffer, sizeof(struct targetPack)); printf("xml length is %d
", ss->XmlLength); if((conns[m].edSize - border_size) > (ss->XmlLength)) { char xmlstr[900]; memset(xmlstr,'\0',900); memcpy(xmlstr, conns[m].totalBuffer+border_size,ss->XmlLength); char *file_name = "xmlFileFromClient.xml"; generateTimeFile(file_name, xmlstr); char xmlbuf[300]; getFDandContent(file_name, testint, xmlbuf); printf("content from client xml:
%s
", xmlbuf); sprintf(content, "%s", xmlbuf); conns[m].recverfd = *testint; } } else if(conns[m].edSize < 0) { printf("conns[m].edSize < 0: %d
", conns[m].edSize); break; } } }

사실 막 히 지 않 는 select 와 막 힌 것 은 정상 적 인 상황 에서 거의 차이 가 나 지 않 는 다.네트워크 나 시스템 자원 이 부족 할 때 만 다르다.
하지만 막 히 지 않 는 io 라면 지금 제 가 이해 하기 로 는 고객 센터 에 문제 가 생 겼 을 때 서버 가 걸 리 지 않 는 것 같 습 니 다.
내 가 프로그램 을 이렇게 쓴 유일한 장점 은 클 라 이언 트 가 완전한 패 킷 을 가지 고 있 으 면 크기 가 다른 많은 패 킷 으로 나 누 는 것 이다.다른 시간 에 보 내 도 서버 는 받 을 수 있 습 니 다.
잘 들 어 봐, 바로 인터넷 지연 이 매우 높 은 말 이 야.나의 프로그램 은 여전히 데 이 터 를 받 을 수 있다.
    유 닉 스 환경 고급 프로 그래 밍 과 유 닉 스 네트워크 프로 그래 밍.문 제 는 항상 그 가 쓴 함수 로 쓰 는 것 이다.복잡성 을 줄 이려 는 것 으로 추정 되 지만 더 이해 하기 어 려 울 줄 은 몰 랐 다.그 가 준 예 를 자세히 보지 못 했다. 인터넷 에서 예 를 찾 았 다. 너무 작은 소아과 나 주석 이 하나 도 없 었 다.오늘 심혈 을 기울 여 구 글 을 썼 습 니 다.
비교적 좋 은 프로그램 을 찾 으 면 주석 같은 것 도 비교적 상세 하 다.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>

#define SERVER_PORT  12345

#define TRUE             1
#define FALSE            0

main (int argc, char *argv[])
{
   int    i, len, rc, on = 1;
   int    listen_sd, max_sd, new_sd;
   int    desc_ready, end_server = FALSE;
   int    close_conn;
   char   buffer[80];
   struct sockaddr_in   addr;
   struct timeval       timeout;
   struct fd_set        master_set, working_set;

   /*************************************************************/
   /* Create an AF_INET stream socket to receive incoming       */
   /* connections on                                            */
   /*************************************************************/
   listen_sd = socket(AF_INET, SOCK_STREAM, 0);
   if (listen_sd < 0)
   {
      perror("socket() failed");
      exit(-1);
   }

   /*************************************************************/
   /* Allow socket descriptor to be reuseable                   */
   /*************************************************************/
   rc = setsockopt(listen_sd, SOL_SOCKET,  SO_REUSEADDR,
                   (char *)&on, sizeof(on));
   if (rc < 0)
   {
      perror("setsockopt() failed");
      close(listen_sd);
      exit(-1);
   }

   /*************************************************************/
   /* Set socket to be non-blocking.  All of the sockets for    */
   /* the incoming connections will also be non-blocking since  */
   /* they will inherit that state from the listening socket.   */
   /*************************************************************/
   rc = ioctl(listen_sd, FIONBIO, (char *)&on);
   if (rc < 0)
   {
      perror("ioctl() failed");
      close(listen_sd);
      exit(-1);
   }

   /*************************************************************/
   /* Bind the socket                                           */
   /*************************************************************/
   memset(&addr, 0, sizeof(addr));
   addr.sin_family      = AF_INET;
   addr.sin_addr.s_addr = htonl(INADDR_ANY);
   addr.sin_port        = htons(SERVER_PORT);
   rc = bind(listen_sd,
             (struct sockaddr *)&addr, sizeof(addr));
   if (rc < 0)
   {
      perror("bind() failed");
      close(listen_sd);
      exit(-1);
   }

   /*************************************************************/
   /* Set the listen back log                                   */
   /*************************************************************/
   rc = listen(listen_sd, 32);
   if (rc < 0)
   {
      perror("listen() failed");
      close(listen_sd);
      exit(-1);
   }

   /*************************************************************/
   /* Initialize the master fd_set                              */
   /*************************************************************/
   FD_ZERO(&master_set);
   max_sd = listen_sd;
   FD_SET(listen_sd, &master_set);

   /*************************************************************/
   /* Initialize the timeval struct to 3 minutes.  If no        */
   /* activity after 3 minutes this program will end.           */
   /*************************************************************/
   timeout.tv_sec  = 3 * 60;
   timeout.tv_usec = 0;

   /*************************************************************/
   /* Loop waiting for incoming connects or for incoming data   */
   /* on any of the connected sockets.                          */
   /*************************************************************/
   do
   {
      /**********************************************************/
      /* Copy the master fd_set over to the working fd_set.     */
      /**********************************************************/
      memcpy(&working_set, &master_set, sizeof(master_set));

      /**********************************************************/
      /* Call select() and wait 5 minutes for it to complete.   */
      /**********************************************************/
      printf("Waiting on select()...
"); rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout); /**********************************************************/ /* Check to see if the select call failed. */ /**********************************************************/ if (rc < 0) { perror(" select() failed"); break; } /**********************************************************/ /* Check to see if the 5 minute time out expired. */ /**********************************************************/ if (rc == 0) { printf(" select() timed out. End program.
"); break; } /**********************************************************/ /* One or more descriptors are readable. Need to */ /* determine which ones they are. */ /**********************************************************/ desc_ready = rc; for (i=0; i <= max_sd && desc_ready > 0; ++i) { /*******************************************************/ /* Check to see if this descriptor is ready */ /*******************************************************/ if (FD_ISSET(i, &working_set)) { /****************************************************/ /* A descriptor was found that was readable - one */ /* less has to be looked for. This is being done */ /* so that we can stop looking at the working set */ /* once we have found all of the descriptors that */ /* were ready. */ /****************************************************/ desc_ready -= 1; /****************************************************/ /* Check to see if this is the listening socket */ /****************************************************/ if (i == listen_sd) { printf(" Listening socket is readable
"); /*************************************************/ /* Accept all incoming connections that are */ /* queued up on the listening socket before we */ /* loop back and call select again. */ /*************************************************/ do { /**********************************************/ /* Accept each incoming connection. If */ /* accept fails with EWOULDBLOCK, then we */ /* have accepted all of them. Any other */ /* failure on accept will cause us to end the */ /* server. */ /**********************************************/ new_sd = accept(listen_sd, NULL, NULL); if (new_sd < 0) { if (errno != EWOULDBLOCK) { perror(" accept() failed"); end_server = TRUE; } break; } /**********************************************/ /* Add the new incoming connection to the */ /* master read set */ /**********************************************/ printf(" New incoming connection - %d
", new_sd); FD_SET(new_sd, &master_set); if (new_sd > max_sd) max_sd = new_sd; /**********************************************/ /* Loop back up and accept another incoming */ /* connection */ /**********************************************/ } while (new_sd != -1); } /****************************************************/ /* This is not the listening socket, therefore an */ /* existing connection must be readable */ /****************************************************/ else { printf(" Descriptor %d is readable
", i); close_conn = FALSE; /*************************************************/ /* Receive all incoming data on this socket */ /* before we loop back and call select again. */ /*************************************************/ do { /**********************************************/ /* Receive data on this connection until the */ /* recv fails with EWOULDBLOCK. If any other */ /* failure occurs, we will close the */ /* connection. */ /**********************************************/ rc = recv(i, buffer, sizeof(buffer), 0); if (rc < 0) { if (errno != EWOULDBLOCK) { perror(" recv() failed"); close_conn = TRUE; } break; } /**********************************************/ /* Check to see if the connection has been */ /* closed by the client */ /**********************************************/ if (rc == 0) { printf(" Connection closed
"); close_conn = TRUE; break; } /**********************************************/ /* Data was recevied */ /**********************************************/ len = rc; printf(" %d bytes received
", len); /**********************************************/ /* Echo the data back to the client */ /**********************************************/ rc = send(i, buffer, len, 0); if (rc < 0) { perror(" send() failed"); close_conn = TRUE; break; } } while (TRUE); /*************************************************/ /* If the close_conn flag was turned on, we need */ /* to clean up this active connection. This */ /* clean up process includes removing the */ /* descriptor from the master set and */ /* determining the new maximum descriptor value */ /* based on the bits that are still turned on in */ /* the master set. */ /*************************************************/ if (close_conn) { close(i); FD_CLR(i, &master_set); if (i == max_sd) { while (FD_ISSET(max_sd, &master_set) == FALSE) max_sd -= 1; } } } /* End of existing connection is readable */ } /* End of if (FD_ISSET(i, &working_set)) */ } /* End of loop through selectable descriptors */ } while (end_server == FALSE); /*************************************************************/ /* Cleanup all of the sockets that are open */ /*************************************************************/ for (i=0; i <= max_sd; ++i) { if (FD_ISSET(i, &master_set)) close(i); } }

좋은 웹페이지 즐겨찾기