vlambda博客
学习文章列表

059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

IO模型分类

059 | 网络编程 | IO模型



059 | 网络编程 | IO模型

阻塞IO

059 | 网络编程 | IO模型

#include <stdio.h>#include <unistd.h>int main(int argc, char const *argv[]){    char buf[32] = {0};     while(1)    {        fgets(buf, 32stdin);        sleep(1);        printf("**********************\n");    }    return 0;}


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

非阻塞IO

059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>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, 32stdin);        sleep(1);        printf("buf = %s\n", buf);        printf("**********************\n");    }    return 0;}

059 | 网络编程 | IO模型

059 | 网络编程 | IO模型


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

使用select实现IO多路复用

059 | 网络编程 | IO模型

059 | 网络编程 | IO模型


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

059 | 网络编程 | IO模型


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

//TCP网络编程之服务器端#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h> //inet_addr htons#include <sys/types.h> //socket#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/select.h>#include <sys/time.h>#define N 128#define ERR_LOG(errmsg) do{\                            perror(errmsg);\                            printf("%s - %s - %d\n", __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 serveraddrclientaddr;    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.x    serveraddr.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, NULLNULLNULL) == -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;}


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

//TCP网络编程之客户端#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h> //inet_addr htons#include <sys/types.h> //socket#include <stdlib.h>#include <string.h>#include <unistd.h>#define N 128//__FILE__ 获取文件名//__func__ 获取函数名//__LINE__ 获取行号#define ERR_LOG(errmsg) do{\                            perror(errmsg);\                             printf("%s - %s - %d\n", __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;}

059 | 网络编程 | IO模型



059 | 网络编程 | IO模型

使用poll实现IO多路复用

059 | 网络编程 | IO模型

059 | 网络编程 | IO模型


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/types.h>#include <unistd.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#include <poll.h>#define N 128//函数宏,主要是用于判断函数是否成功执行#define errlog(errmsg) do{perror(errmsg); exit(1);}wint main(int argc, const char *argv[]){ int sockfd, acceptfd; struct sockaddr_in serveraddrclientaddr; char buf[N] = {}; //初始化结构体 memset(&serveraddr, 0sizeof(serveraddr)); memset(&clientaddr, 0sizeof(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 *)&clienta0)   {    errlog("fail to accept");   }   printf("%s ---> %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(cli  }  } close(acceptfd); close(sockfd); return 0;}


059 | 网络编程 | IO模型


059 | 网络编程 | IO模型

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#define errlog(errmsg) do{perror(errmsg); exit(1);}whilint 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.13 serveraddr.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;}

059 | 网络编程 | IO模型



059 | 网络编程 | IO模型

信号驱动IO

059 | 网络编程 | IO模型


059 | 网络编程 | IO模型