059 | 网络编程 | IO模型
IO模型分类
阻塞IO
int main(int argc, char const *argv[]){char buf[32] = {0};while(1){fgets(buf, 32, stdin);sleep(1);printf("**********************\n");}return 0;}
非阻塞IO
int main(int argc, char const *argv[]){char buf[32] = {0};//使用fcntl函数设置非阻塞IO//注意:当涉及到位操作或者操作寄存器时,由于标志位有很多,//我们想修改的标志位可能只是其中的一部分,所以在修改的时候//只能修改要操作的位,其他位不要操作,所以一般要执行读、改//第一步:读取原本的标志位int flags;if((flags = fcntl(0, F_GETFL)) == -1){perror("fail to fcntl");exit(1);}//printf("flags = %#o\n", flags);//第二步:修改标志位flags = flags | O_NONBLOCK;//第三步:将新的标志位写回去if(fcntl(0, F_SETFL, flags) == -1){perror("fail to fcntl");exit(1);}sleep(5);while(1){fgets(buf, 32, stdin);sleep(1);printf("buf = %s\n", buf);printf("**********************\n");}return 0;}
使用select实现IO多路复用
//TCP网络编程之服务器端perror(errmsg);\printf(, __FILE__, __func__, __LINE_);\exit(1);\}while(0)int main(int argc, char const *argv[]){if(argc != 3){fprintf(stderr, "Usage:%s <ip> <port>\n", argv[0]);exit(1);}int sockfd;struct sockaddr_in serveraddr, clientaddr;socklen_t addrlen = sizeof(serveraddr);char buf[N] = {0};int acceptfd;//第一步:创建套接字if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ERR_LOG("fail to socket");}//第二步:填充服务器网络信息结构体//inet_addr:将点分十进制字符串转化为整形数据//htons:将主机字节序转化为网络字节序//atoi:将数字型字符串转化为整形数据serveraddr.sin_family = AF_INET; //协议族serveraddr.sin_addr.s_addr = inet_addr(argv[1]); //自己的ip地址或者27.x.x.xserveraddr.sin_port = htons(atoi(argv[2]));//第三步:将套接字与服务器网络信息结构体绑定if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) == -1){ERR_LOG("fail to bind");}//第四步:将套接字设置为被动监听状态if(listen(sockfd, 5) == -1){ERR_LOG("fail to listen");}//使用select实现IO多路复用//IO多路复用:解决一个代码中有多个阻塞函数,让多个阻塞函数独立运行,相互没有影响//第1步:创建保存指定文件描述符的集合并清空fd_set readfds;FD_ZERO(&readfds);int maxfd = sockfd;while(1){//第2步:将要操作的文件描述符添加到集合中FD_SET(0, &readfds);FD_SET(sockfd, &readfds);//第3步:调用select函数阻塞等待文件描述符准备就绪if(select(maxfd+1, &readfds, NULL, NULL, NULL) == -1){ERR_LOG("fail to select");}//select函数如果成功返回,意味着有文件描述符准备就绪,//select函数会将没有准备就绪的文件描述符从集合中移除,//所以执行完毕之后集合中只剩下准备就绪的文件描述符,//判断是哪个就执行相应的操作.if(FD_ISSET(0, &readfds) == 1){if(fgets(buf, N, stdin) == NULL){ERR_LOG("fail to fgets");}buf[strlen(buf) - 1] = '\0';printf("buf = %s\n", buf);}if(FD_ISSET(sockfd, &readfds) == 1){if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) ==-1){ERR_LOG("fail to accept");}printf("%s:%d连接了\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));}}return 0;}
//TCP网络编程之客户端//__FILE__ 获取文件名//__func__ 获取函数名//__LINE__ 获取行号perror(errmsg);\printf(, __FILE__, __func__, __LINE_);\exit(1);\}while(0)int main(int argc, char const *argv[]){if(argc < 3){fprintf(stderr, "Usage:%s <ip> <port>\n", argv[0]);exit(1);}int sockfd;struct sockaddr_in serveraddr;socklen_t addrlen = sizeof(serveraddr);//第一步:创建套接字if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ERR_LOG("fail to socket");}//第二步:填充服务器网络信息结构体//inet_addr:将点分十进制字符串转化为整形数据//htons:将主机字节序转化为网络字节序//atoi:将数字型字符串转化为整形数据serveraddr.sin_family = AF_INET; //协议族serveraddr.sin_addr.s_addr = inet_addr(argv[1]); //服务器的ip地址serveraddr.sin_port = htons(atoi(argv[2])); //服务器的端口号//第三步:发送客户端连接请求if(connect(sockfd, (struct sockaddr *)&serveraddr, addrlen)==-1){ERR_LOG("fail to connect");}return 0;}
使用poll实现IO多路复用
//函数宏,主要是用于判断函数是否成功执行int main(int argc, const char *argv[]){int sockfd, acceptfd;struct sockaddr_in serveraddr, clientaddr;char buf[N] = {};//初始化结构体memset(&serveraddr, 0, sizeof(serveraddr));memset(&clientaddr, 0, sizeof(clientaddr));if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){errlog("fail to socket");}serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeo< 0){errlog("fail to bind");}if(listen(sockfd, 10) < 0){errlog("fail to listen");}socklen_t addrlen = sizeof(struct sockaddr_in);//使用poll实现IO多路复用//定义结构体数组并添加文件描述符以及请求的事件struct pollfd fds[2];fds[0].fd = 0;fds[0].events = POLLIN;fds[1].fd = sockfd;fds[1].events = POLLIN;int numfd = 2;while(1){//调用poll函数阻塞等待文件描述符准备就绪if(poll(fds, numfd, -1) < 0){errlog("fail to poll");}//分别判断返回的事件是否是有数据可读if((fds[0].revents & POLLIN) == 1) //0x1231 == 0x0{fgets(buf, N, stdin);buf[strlen(buf) - 1] = '\0';printf("buf >>> %s\n", buf);}if(fds[1].revents & POLLIN){if((acceptfd = accept(sockfd, (struct sockaddr *)&clienta< 0){errlog("fail to accept");}printf("%s ---> %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(cli}}close(acceptfd);close(sockfd);return 0;}
int main(int argc, const char *argv[]){int sockfd;struct sockaddr_in serveraddr;//一.创建一个套接字(文件描述符)if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){errlog("fail to socket");}//二.填充网络信息结构体//协议族serveraddr.sin_family = AF_INET;//ip地址//serveraddr.sin_addr.s_addr = inet_addr("192.168.0.13serveraddr.sin_addr.s_addr = inet_addr(argv[1]);//端口号(进程确定)//使用htons函数将主机字节序转化为网络字节序//使用atoi函数将字符串转化为网络能够识别的整型数据//serveraddr.sin_port = htons(9999);serveraddr.sin_port = htons(atoi(argv[2]));//三.与服务器建立连接if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeor)) < 0){errlog("fail to connect");}close(sockfd);return 0;}
信号驱动IO
