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.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, 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.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, sizeo
r)) < 0)
{
errlog("fail to connect");
}
close(sockfd);
return 0;
}
信号驱动IO