I/O 재사용: 비동기식 채팅
8153 단어 I/O
에서의 동기화 채팅 프로그램에서 TCP 고객이 표준 입력과 TCP 소켓 두 개의 입력을 동시에 처리하는 것을 보았습니다.고객이 표준 입력 fgets 호출에 막혔을 때 서버 프로세스가 죽는 것을 고려하여 서버 TCP는 고객 TCP에 FIN을 보내지만 고객 프로세스는 표준 입력 읽기 프로세스에 막힌다. 이 EOF는 플러그인에서 읽을 때까지 볼 수 없다.이러한 프로세스는 코어가 지정한 입출력 조건을 발견하면 프로세스에 알릴 수 있도록 코어에 미리 알려주는 기능을 필요로 합니다.이 능력은 I/O 복용이라고 하는데 select와poll 두 함수에 의해 지원됩니다.
입출력 재사용은 일반적으로 다음과 같은 경우에 적용됩니다.
2.select 함수
select 함수는 프로세스가 여러 이벤트 중 임의의 발생을 기다릴 수 있도록 합니다. 한 개 이상의 이벤트가 발생하거나 지정된 시간이 지나야만 깨울 수 있습니다.
#include<sys/select.h>
#include<sys/time.h>
int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);
반환: 준비 설명자가 있으면 그 수를 반환하고, 시간을 초과하면 0을 반환하고, 오류가 발생하면 1을 반환합니다.
헤더 파일
maxfdp1 매개 변수는 테스트를 포함하는 설명자 개수를 지정합니다. 그 값은 테스트를 포함하는 최대 설명자 더하기 1, 설명자 0, 1, 2,...,maxfdp1-1 모두 테스트됩니다.
중간 세 개의 매개 변수readset, writeset, exceptset은 내부 테스트를 읽기/쓰기, 이상 조건에 대한 설명자를 지정합니다.
void FD_ZERO(fd_set *fdset); //clear all bits in fdset
void FD_SET(int fd,fd_set *fdset); //turn on the bit for fd in fdset
void FD_CLR(int fd,fd-set *fdset); //turn off the bit for fd in fdset
int FD_ISSET(int fd,fd_set *fdset); //is the bit for fd on in fdset?
그 중에서 묘사부호의 초기화는 매우 중요하다.
파라미터timeout은 내부 핵이 지정한 설명자에 있는 모든 준비가 얼마나 걸릴지 알려줍니다. timeval 구조는 이 시간의 초수와 미묘수를 지정하는 데 사용됩니다.
struct timeval
{
long tv_sec; //second
long tv_usec; //microsecond
};
이 매개 변수는 세 가지 가능성이 있다.
셋.비동기식 채팅 프로그램
TCP 비동기 채팅 프로그램을 작성하여 이해를 깊이 있게 하다.
서버 코드:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include <unistd.h>
#include<time.h>
#define MAXSIZE 1024
#define PORT 8080
#define BACKLOG 10
int main(int argc,char **argv)
{
int listenfd,connfd;
struct sockaddr_in servaddr,cliaddr;
socklen_t len;
char message[MAXSIZE];
fd_set rfds;
// struct timeval tv;
int retval,maxfd=-1;
if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket");
exit(1);
}
else printf("socket create success!
");
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(PORT);
if((bind(listenfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr)))==-1)
{
perror("bind");
exit(1);
}
else printf("bind success!
");
if(listen(listenfd,BACKLOG)==-1)
{
perror("listen");
exit(1);
}
else printf("sever is listening!
");
for( ; ; )
{
printf(" ...
");
len=sizeof(struct sockaddr);
if((connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&len))==-1)
{
perror("accept");
exit(1);
}
else printf(" :%s: %d
",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
printf(" !
");
for( ; ; )
{
FD_ZERO(&rfds);
FD_SET(0,&rfds);
maxfd=0;
FD_SET(connfd,&rfds);
if(connfd>maxfd) maxfd=connfd;
retval=select(maxfd+1,&rfds,NULL,NULL,NULL);
if(retval==-1)
{
printf("select !%s",strerror(errno));
break;
}
else if(retval==0)
{
printf(" ...
");
continue;
}
else
{
if(FD_ISSET(0,&rfds))
{
bzero(message,MAXSIZE);
printf(" :");
fgets(message,MAXSIZE,stdin);
if(!strncasecmp(message, "quit", 4))
{
printf(" !
");
break;
}
else len=send(connfd,message,strlen(message),0);
if(len<0)
{
printf(" ");
break;
}
}
if(FD_ISSET(connfd,&rfds))
{
bzero(message,MAXSIZE);
len=recv(connfd,message,MAXSIZE,0);
if(len>0) printf(" :%s",message);
else
{
if(len<0) printf(" !
");
else printf(" !
");
break;
}
}
}
}
close(connfd);
printf(" [Y/N]:");
bzero(message,MAXSIZE);
fgets(message,MAXSIZE,stdin);
if(!strncasecmp(message, "Y", 1))
{
printf(" !
");
break;
}
}
close(listenfd);
return 0;
}
클라이언트 코드:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#define MAXSIZE 1024
#define PORT 8080
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
socklen_t len;
fd_set rfds;
// struct timeval tv;
int retval,maxfd=-1;
char message[MAXSIZE];
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket");
exit(1);
}
else printf("socket create success!
");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
inet_aton(argv[1],&servaddr.sin_addr);
if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr))==-1)
{
perror("connect");
exit(1);
}
else printf("conncet success!
");
for( ; ; )
{
FD_ZERO(&rfds);
FD_SET(0,&rfds);
maxfd=0;
FD_SET(sockfd,&rfds);
if(sockfd>maxfd) maxfd=sockfd;
retval=select(maxfd+1,&rfds,NULL,NULL,NULL);
if(retval==-1)
{
printf("select !%s",strerror(errno));
break;
}
else if(retval==0)
{
printf(" ...
");
continue;
}
else
{
if(FD_ISSET(sockfd,&rfds))
{
bzero(message,MAXSIZE);
len=recv(sockfd,message,MAXSIZE,0);
if(len>0)
printf(" :%s",message);
else
{
if(len<0) printf(" !
");
else printf(" !
");
break;
}
}
if(FD_ISSET(0,&rfds))
{
bzero(message,MAXSIZE);
printf(" :");
fgets(message,MAXSIZE,stdin);
if(!strncasecmp(message, "quit", 4))
{
printf("client !
");
break;
}
else len = send(sockfd,message,strlen(message),0);
if(len<0)
{
printf(" !
");
break;
}
}
}
}
close(sockfd);
return 0;
}
컴파일:
gcc -Wall server.c -o server
gcc -Wall client.c -o client
서버 실행 결과:
./server
socket create success!
bind success!
sever is listening!
...
:127.0.0.1: 50235
!
:
: , !
: 。
: , !
: :
:Byebye!
!
[Y/N]:Y
!
클라이언트 실행 결과:
./client 127.0.0.1
socket create success!
conncet success!
: , !
: 。
: :
: , !
:Byebye!
:quit
:client !
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
scsi i/o error텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.