IO分为同步、异步,阻塞、非阻塞,两两组合成4种模型。
2. 同步阻塞IO 2.1 阻塞的原因一个常见的问题是IO对请求没有准备好:例如调用读请求的时候可能设备上没有数据,但是将来可能有;调用写请求时可能舍妹没有准备好接收数据,一会儿可能buffer清空就好了。调用过程一般不去理会这些问题,如果程序员仅仅要求在请求返回时工作做好,那么驱动设备就应该阻塞这个请求的进程,使他陷入睡眠状态。
2.2 什么是睡眠当一个进程处于睡眠态, 意味着它被移除调度队列,直到这个状态被改变之前,CPU都不会处理这个进程。有几个注意事项:
不要在原子上下文中sleep
无法保证精确的睡眠时间
只有在确定其他进程/内核会唤醒自己时,才能睡眠
2.3 同步阻塞IO的编程模型 3. 同步阻塞IO的网络编程代码示例 /* A simple server in the internet domain using TCP The port number is passed as an argument */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> void error(const char *msg) { perror(msg); exit(1); } int main(int argc, char *argv[]) { int sockfd, newsockfd, portno; socklen_t clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n; if (argc < 2) { fprintf(stderr,"ERROR, no port provided\n"); exit(1); } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding"); listen(sockfd,5); clilen = sizeof(cli_addr); newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) error("ERROR on accept"); bzero(buffer,256); n = read(newsockfd,buffer,255); if (n < 0) error("ERROR reading from socket"); printf("Here is the message: %s\n",buffer); n = write(newsockfd,"I got your message",18); if (n < 0) error("ERROR writing to socket"); close(newsockfd); close(sockfd); return 0; }