目录
2> 通过设置文件描述符的属性,把文件描述符的属性设置为非阻塞
3》信号驱动IO/异步IO:异步通知方式,需要底层驱动的支持
【1】UDP
1》通信流程
2》函数接口
1> recvfrom
2> sendto
3》代码展示
1> 服务器代码
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char buf[128] = {0};
int ret;
// 1.创建数据报套接字(socket)------------------》有手机
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket err");
return -1;
}
printf("sockfd:%d\n", sockfd);
// 2.指定网络信息--------------------------------------》有号码
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_I
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = INADDR_ANY;
int len = sizeof(caddr);
// 3.绑定套接字(bind)------------------------------》绑定手机
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind err");
return -1;
}
printf("bind okk\n");
// 4.接收、发送消息(recvfrom sendto)-------》收短信
while (1)
{
// 最后两个参数存放:发送消息的人的信息
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &len);
if (ret < 0)
{
perror("recvfrom err");
return -1;
}
else
{
printf("ip:%s port:%d buf:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port), buf);
memset(buf, 0, sizeof(buf));
}
}
// 5.关闭套接字(close)----------------------------》接收完毕
close(sockfd);
return 0;
}
2> 客户端代码
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char buf[128] = {0};
int ret;
// 1.创建数据报套接字(socket)------------------》有手机
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket err");
return -1;
}
printf("sockfd:%d\n", sockfd);
// 2.指定网络信息--------------------------------------》有号码
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = inet_addr("192.168.253.145");
int len = sizeof(caddr);
// 4.接收、发送消息(recvfrom sendto)-------》收短信
while (1)
{
fgets(buf, sizeof(buf), stdin);
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
if (strcmp(buf, "quit") == 0)
{
break;
}
sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, sizeof(saddr));
memset(buf,0,sizeof(buf));
}
// 5.关闭套接字(close)----------------------------》接收完毕
close(sockfd);
return 0;
}
注意:
【2】Linux IO 模型
4种:阻塞IO、非阻塞IO、信号驱动IO(异步IO)、IO多路复用
场景假设一
1》阻塞式IO:最常见、效率低、不耗费CPU
udp丢包
tcp粘包
tcp拆包
2》 非阻塞 IO:轮询、耗费CPU,可以处理多路IO
设置非阻塞的方式
1> 通过函数自带参数设置
2> 通过设置文件描述符的属性,把文件描述符的属性设置为非阻塞
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
//1.获取文件描述符的原有属性
int flags = fcntl(0,F_GETFL);
//2.修改文件描述符的属性
flags = flags | O_NONBLOCK;
//3.设置文件描述符的属性
fcntl(0,F_SETFL,flags);
char buf[32];
while(1)
{
if(fgets(buf,sizeof(buf),stdin) == NULL)
{
perror("err\n");
}
else
{
printf("buf: %s\n",buf);
}
sleep(1);
}
return 0;
}
3》信号驱动IO/异步IO:异步通知方式,需要底层驱动的支持
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
int fd;
void handler(int sig)
{
char buf[32];
printf("------------------------\n");
read(fd, buf, sizeof(buf));
printf("mouse: %s\n", buf);
}
int main(int argc, char const *argv[])
{
fd = open("/dev/input/mouse1", O_RDONLY);
if (fd < 0)
{
perror("fd err\n");
return -1;
}
// 1.将进程号和文件描述符交给内核
fcntl(fd, __F_SETOWN, getpid());
// 2.设置异步通知
int flags = fcntl(fd, F_GETFL);
flags = flags | O_ASYNC;
fcntl(fd, F_SETFL, flags);
// 3.捕捉信号,做逻辑处理
signal(SIGIO, handler);
while (1)
{
printf("111\n");
sleep(1);
}
return 0;
}
4》三种模型对比