반성: 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);
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
React 구성 요소에서 소켓 이벤트 리스너가 여러 번 실행됩니다.기본적이지만 종종 간과되는 사이드 프로젝트를 하면서 배운 것이 있습니다. 이 프로젝트에는 단순히 두 가지 주요 부분이 포함되어 있습니다. 프런트 엔드: 반응 및 재료 UI 백엔드: Express, Typescript...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.