IO 차단 과 비 차단 에 관 한 자질구레한 지식
블록 이라는 개념 을 막는다.프로 세 스 가 막 힌 시스템 함 수 를 호출 할 때 이 프로 세 스 는 수면 (Sleep) 상태 에 있 습 니 다. 이 때 커 널 은 다른 프로 세 스 를 실행 합 니 다. 이 프로 세 스 가 기다 리 는 이벤트 가 발생 할 때 까지 (예 를 들 어 네트워크 에서 패 킷 을 받 거나 sleep 에서 지정 한 수면 시간 을 호출 할 때) 계속 실 행 될 수 있 습 니 다.수면 상태 와 상대 적 으로 실행 (Running) 상태 로 리 눅 스 커 널 에서 실행 상태 에 있 는 프로 세 스 는 두 가지 상황 으로 나 뉜 다.
스케줄 링 실행 중 입 니 다.CPU 는 이 프로 세 스 의 컨 텍스트 환경 에 있 습 니 다. 프로그램 카운터 (eip) 에는 이 프로 세 스 의 명령 주소 가 저장 되 어 있 습 니 다. 유 니 버 설 레지스터 에는 이 프로 세 스 연산 과정의 중간 결 과 를 저장 하고 있 습 니 다. 이 프로 세 스 의 명령 을 실행 하고 있 습 니 다. 이 프로 세 스 의 주소 공간 을 읽 고 있 습 니 다.
준비 상태.이 프로 세 스 는 어떤 이벤트 가 발생 할 때 까지 기다 릴 필요 가 없습니다. 언제든지 실행 할 수 있 지만 CPU 는 다른 프로 세 스 를 잠시 실행 하고 있 기 때문에 이 프로 세 스 는 준 비 된 대기 열 에서 커 널 스케줄 링 을 기다 리 고 있 습 니 다.시스템 에 여러 개의 준 비 된 프로 세 스 가 동시에 있 을 수 있 습 니 다. 그러면 누가 실행 할 것 입 니까?커 널 의 스 케 쥴 링 알고리즘 은 우선 순위 와 시간 영 화 를 기반 으로 하고 모든 프로 세 스 의 운행 상황 에 따라 우선 순위 와 시간 영 화 를 동적 으로 조정 하여 모든 프로 세 스 가 비교적 공정 하 게 기 회 를 얻 을 수 있 도록 하 는 동시에 사용자 체험 을 병행 하여 사용자 와 상호작용 하 는 프로 세 스 의 응답 이 너무 느 려 서 는 안 됩 니 다.
2, IO 모드 설정
일반적으로 하나의 socket 이 차단 모드 인지 비 차단 모드 인지 두 가지 방식 이 있 습 니 다.
방법 1. fcntl 설정;
flags = fcntl(sockfd, F_GETFL, 0); //파일 의 flags 값 을 가 져 옵 니 다.
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //비 차단 모드 로 설정 하기;
flags = fcntl(sockfd,F_GETFL,0);
fcntl(sockfd,F_SETFL,flags&~O_NUNBLOCK); //차단 모드 로 설정 하기;
방법 2, recv, send 함수 의 마지막 flag 매개 변 수 는 MSG 로 설정 할 수 있 습 니 다.DONTWAIT
임시로 sockfd 를 비 차단 모드 로 설정 합 니 다. 원래 차단 이 든 비 차단 이 든.
recv(sockfd, buff, buff_size,MSG_DONTWAIT); //비 차단 모드 메시지 전송
send(scokfd, buff, buff_size, MSG_DONTWAIT); //비 차단 모드 메시지 수락
3, 읽 기 (read / recv / msgrcv):
차단 과 비 차단 의 차 이 는 데이터 가 도착 하지 않 았 을 때 바로 돌아 오 느 냐 하 는 것 이다.
read 든 recv 든 데 이 터 를 바 텀 버퍼 copy 에서 우리 가 지정 한 위치 로 만 책임 집 니 다.
막 힌 상태 에서:
1. 데이터 가 네트워크 버퍼 에서 계속 기다 리 는 것 을 발견 하지 못 하면,
2. 데이터 가 발견 되면 사용자 가 지정 한 버퍼 에 데 이 터 를 읽 습 니 다. 그러나 이때 읽 은 데이터 의 양 이 적 고 매개 변수 에서 지정 한 길이 보다 작 으 며 read 는 계속 기다 리 지 않 고 바로 돌아 갑 니 다.
read 의 원칙 은 데이터 가 지 정 된 길 이 를 초과 하지 않 을 때 얼마나 읽 는 지, 데이터 가 없 으 면 계속 기다 리 는 것 이다.따라서 일반적인 상황 에서 우 리 는 데 이 터 를 읽 을 때 순환 적 으로 읽 는 방식 으로 데 이 터 를 읽 어야 한다. 왜냐하면 한 번 의 read 가 끝나 면 우리 가 필요 로 하 는 길이 의 데 이 터 를 읽 을 수 없 기 때문이다. read 가 끝나 면 읽 은 데이터 의 길 이 를 판단 하고 다시 읽 어야 하 는 지 여 부 를 결정 해 야 한다.
차단 되 지 않 은 상태 에서:
1. 데이터 가 없 는 것 을 발견 하면 바로 돌아 갑 니 다.
2. 데이터 가 있 는 것 을 발견 하면 읽 은 만큼 처리 합 니 다.
따라서 읽 은 데이터 의 길 이 를 한 번 판단 하고 다시 읽 어야 할 지 여 부 를 결정 해 야 합 니 다.
4, 쓰기 (send / write / msgsnd):
쓰기 의 본질 도 전송 작업 을 하 는 것 이 아니 라 사용자 상태의 데 이 터 를 시스템 밑바닥 으로 복사 한 다음 에 시스템 에서 전송 작업 을 한다. send, write 는 성공 적 으로 되 돌 아 왔 다. 데 이 터 는 copy 의 도대체 층 버퍼 가 되 었 음 을 나타 내 는 것 이지 데이터 가 이미 보 냈 다 는 것 을 나타 내 는 것 이 아니 라 사각형 포트 가 데 이 터 를 연결 했다 는 것 을 나타 내 는 것 이 아니다.
막 힌 상태 에서 write 는 데 이 터 를 다 보 냅 니 다.(단, 중 단 될 수 있 습 니 다)
막 힌 상황 에서 write 가 끝 날 때 까지 모든 데 이 터 를 되 돌려 줍 니 다. 이 행 위 는 읽 기 동작 과 다 릅 니 다.
비 차단 쓰기 의 경우 쓸 수 있 는 만큼 쓰 는 전략 을 사용 합 니 다. 읽 기와 다른 점 은 읽 을 수 있 는 만큼 읽 는 것 이 네트워크 에서 보 내 는 쪽 에 데이터 가 전송 되 는 지 여 부 를 기준 으로 하지만 쓸 수 있 는 만큼 쓸 수 있 는 것 이 로 컬 네트워크 차단 상황 을 기준 으로 합 니 다. 네트워크 차단 이 심 할 때 네트워크 층 은 쓰기 에 충분 한 메모리 가 없습니다.이 럴 때 는 쓰기 에 성공 하지 못 하 는 경우 가 있 습 니 다. 막 힌 상황 에서 가능 한 한 (중 단 될 수 있 습 니 다) 데이터 가 모두 전 송 될 때 까지 기다 리 고 있 습 니 다. 막 히 지 않 는 상황 에 대해 서 는 한 번 에 쓰 는 만큼 계산 하고 중단 되 지 않 은 상황 에서 도 write 가 일부 상황 에 이 를 수 있 습 니 다.
Server:
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#define BUFSIZE 128
int main(int argc,char *argv[]){
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
int i,byte;
char char_send[BUFSIZE];
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&server_address, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(7838);
server_address.sin_addr.s_addr = INADDR_ANY;
server_len = sizeof(server_address);
if ((bind(server_sockfd, (struct sockaddr *)&server_address, server_len))== -1) {
perror("bind");
exit(EXIT_FAILURE);
}
listen(server_sockfd, 5);
printf("server waiting for connect
");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, (socklen_t *)&client_len);
for(i=0;i<5;i++){
memset(char_send,'\0',BUFSIZE);
printf("input message to send:");
fgets(char_send,BUFSIZE,stdin);
if((byte=send(client_sockfd,char_send,strlen(char_send),0))==-1){
perror("send");
exit(EXIT_FAILURE);
}
memset(char_send,'\0',BUFSIZE);
//
byte = recv(client_sockfd, char_send, BUFSIZE,MSG_DONTWAIT);
if(byte > 0){
printf("get %d message:%s", byte, char_send);
byte=0;
}else if(byte<0){
if(errno==EAGAIN){
errno=0;
continue;
}else{
perror("recv");
exit(EXIT_FAILURE);
}
}
}
shutdown(client_sockfd,2);
shutdown(server_sockfd,2);
}
Client:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#define MAXBUF 128
int main(int argc, char **argv){
int sockfd, ret, i;
struct sockaddr_in dest, mine;
char buffer[MAXBUF + 1];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket");
exit(EXIT_FAILURE);
}
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(7838);
if(argc<2){
printf("Usage: %s <dest ip> <src ip>",argv[0]);
exit(1);
}
if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0){
perror(argv[1]);
exit(1);
}
bzero(&mine, sizeof(mine));
mine.sin_family = AF_INET;
mine.sin_port = htons(7839);
if (inet_aton(argv[2], (struct in_addr *) &mine.sin_addr.s_addr) == 0){
perror(argv[2]);
exit(EXIT_FAILURE);
}
if (bind(sockfd, (struct sockaddr *) &mine, sizeof(struct sockaddr)) == -1){
perror(argv[3]);
exit(EXIT_FAILURE);
}
printf("will connect!
");
if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
perror("Connect ");
exit(EXIT_FAILURE);
}
// sock
if(fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
perror("fcntl");
exit(EXIT_FAILURE);
}
while(1){
bzero(buffer, MAXBUF + 1);
// socket ,
ret = recv(sockfd, buffer, MAXBUF, 0);
if(ret > 0){
printf("get %d message:%s", ret, buffer);
ret=0;
}else if(ret < 0) {
if(errno == EAGAIN) {
errno=0;
continue;
}else{
perror("recv");
exit(EXIT_FAILURE);
}
}
memset( buffer,'\0',MAXBUF+1);
printf("input message to send:");
fgets( buffer,MAXBUF,stdin);
if((ret=send(sockfd,buffer,strlen(buffer),0))==-1){
perror("send");
exit(EXIT_FAILURE);
}
}
close(sockfd);
return 0;
}
원본:
http://blog.csdn.net/heyutao007/article/details/6733029
http://blog.csdn.net/heyutao007/article/details/6732928
http://blog.csdn.net/fansongy/article/details/6898577
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
java 입출력 I/O스트림(stream) 자바에서 입출력을 수행하려면 두 대상을 연결하고 데이터를 전송할 수 있는 무언가가 필요한데 이것을 스트림(stream)이라고 정의했다. 스트림은 단방향 통신만 가능하기 때문에 하나의 스트림으로 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.