嵌入式学习Day36---Linux软件编程---网络编程

2024-08-21 02:52

本文主要是介绍嵌入式学习Day36---Linux软件编程---网络编程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、TCP并发模型

1.1.阻塞IO

1.2.非阻塞IO

1.步骤

2.函数接口

3.实例

1.3.异步IO

1.步骤

2.函数接口

3.实例

1.4.多路复用IO 

1.select

函数接口:

实例 

2.poll

3.epoll

 二、总结


 

一、TCP并发模型

1.1.阻塞IO

 CPU占用率低,等待资源时将任务挂起,不占用CPU资源,等到拿到资源后继续向下执行;

1.2.非阻塞IO

 能够让任务不阻塞,效率低,因为没有数据时,CPU一直空转;

1.步骤

        1)获取文件描述符的IO状态

        2)设置文件描述符的IO状态为非阻塞

        3) 将该IO状态写入文件描述符

2.函数接口

        fctnl() 具体使用看下面的例子

3.实例

        此处,以写入端通过管道向接收端传递信息,接收端可以接收管道信息,并且也可以从终端接收。将管道和终端的描述符均设置为非阻塞,实现,接收端一边可以接收写入端的信息,一边可以接收终的信息。(核心在read.c)

write.c

#include "../head.h"int main(void)
{int fd = 0;int ret = 0;ssize_t nsize = 0;char buff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_WRONLY);if (fd == -1){perror("open");return -1;}while(1){memset(buff, 0, sizeof(buff));gets(buff);nsize = write(fd, buff, strlen(buff)+1);if (nsize == -1){perror("write");return -1;}}close(fd);return 0;
}

 read.c

#include "../head.h"int main(void)
{   int fd = 0;int flag = 0;ssize_t nsize = 0;char *pnisze = NULL;char buf[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if (-1 == fd){perror("fail to open");return -1;}//获得文件描述符的熟悉flag = fcntl(fd, F_GETFL);//设置文件描述符为非阻塞flag |= O_NONBLOCK;//设置文件描述符fcntl(fd, F_SETFL, flag);/*设置终端IO*/flag = fcntl(0, F_GETFL);flag |= O_NONBLOCK;fcntl(0, F_SETFL, flag);while (1){memset(buf, 0, sizeof(buf));nsize = read(fd, buf, sizeof(buf));if (nsize > 0){printf("WRITE = %s\n", buf);}memset(buf, 0, sizeof(buf));pnisze = gets(buf);if (pnisze != NULL){printf("STDIN = %s\n", buf);}}close(fd);return 0;
}

1.3.异步IO

        将一个文件描述符设定为异步IO,当IO有事件发生时,内核会向用户层发送SIGIO信号提醒用户层处理事件  

1.步骤

        1)获取文件描述符的IO状态

        2)设置文件描述符的IO状态为异步

        3) 将该IO状态写入文件描述符

        4)处理IO信号

2.函数接口

        fctnl() 具体使用看下面的例子

        signal(SIGIO, handel); 接收文件描述符信号 

3.实例

        此处,以写入端通过管道向接收端传递信息,接收端可以接收管道信息,并且也可以从终端接收。将管道描述符设置为异步,终端信息正常接收,当管道里面有了一个信息时,发送SIGIO信号。(核心在read.c)

write.c

#include "../head.h"int main(void)
{int fd = 0;int ret = 0;ssize_t nsize = 0;char buff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_WRONLY);if (fd == -1){perror("open");return -1;}while(1){memset(buff, 0, sizeof(buff));gets(buff);nsize = write(fd, buff, strlen(buff)+1);if (nsize == -1){perror("write");return -1;}}close(fd);return 0;
}

read.c

#include "../head.h"int fd = 0;
void handler(int sig)
{char tmpbuff[1024] = {0};memset(tmpbuff, 0, sizeof(tmpbuff));read(fd, tmpbuff, sizeof(tmpbuff));printf("RECV:%s\n", tmpbuff);
}
int main(void)
{   int flag = 0;ssize_t nsize = 0;char *pnisze = NULL;char buf[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if (-1 == fd){perror("fail to open");return -1;}//获取管道的IO状态flag = fcntl(fd, F_GETFL);//设置为异步flag |= O_ASYNC;fcntl(fd, F_SETFL, flag);//通知当前进程管道信号来了fcntl(fd, F_SETOWN, getpid());signal(SIGIO, handler);while (1){memset(buf, 0, sizeof(buf));pnisze = gets(buf);if (pnisze != NULL){printf("STDIN = %s\n", buf);}}close(fd);return 0;
}

 

1.4.多路复用IO 

1.select

函数接口:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);功能:监听文件描述符是否有事件发生参数:nfds:最大文件描述符的值 + 1 readfds:读文件描述符集合writefds:写文件描述符集合exceptfds:异常文件描述符集合timeout:超时时间返回值:成功返回产生事件的文件描述符个数失败返回-1 timeout时间到达仍然没有产生的事件返回0 
        void FD_CLR(int fd, fd_set *set);功能:将fd从集合中清除int  FD_ISSET(int fd, fd_set *set);功能:判断fd是否仍在文件描述符集合中void FD_SET(int fd, fd_set *set);功能:将fd加入文件描述符集合中void FD_ZERO(fd_set *set);功能:将文件描述符集合清0 
实例 

client.c

#include "head.h"int CreateTcpConnection(const char *pip, int port)
{int sockfd = 0;int ret = 0;struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(pip);sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){return -1;}ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (-1 == ret){return -1;}return sockfd;
}int HandleConnection(int sockfd)
{char tmpbuff[4096] = {0};static int cnt = 0;ssize_t nsize = 0;sprintf(tmpbuff, "hello world --- %d", cnt);nsize = send(sockfd, tmpbuff, strlen(tmpbuff), 0);if (-1 == nsize){return -1;}cnt++;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(sockfd, tmpbuff, sizeof(tmpbuff), 0);  if (-1 == nsize){return -1;}else if (0 == nsize){return 0;}printf("RECV:%s\n", tmpbuff);return nsize;
}int main(void)
{int sockfd = 0;int ret = 0;sockfd = CreateTcpConnection(SER_IP, SER_PORT);if (-1 == sockfd){printf("连接服务器异常\n");return -1;}while (1){ret = HandleConnection(sockfd);if (-1 == ret){printf("连接出错!\n");break;}else if (0 == ret){printf("连接关闭\n");break;}sleep(1);}close(sockfd);return 0;
}

server.c

#include "head.h"int CreateListenSocket(const char *pip, int port)
{int sockfd = 0;int ret = 0;struct sockaddr_in seraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){return -1;}seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(pip);ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (-1 == ret){return -1;}ret = listen(sockfd, 10);if (-1 == ret){return -1;}return sockfd;
}int HandleConnection(int confd)
{char tmpbuff[4096] = {0};ssize_t nsize = 0;nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);if (-1 == nsize){return -1;}else if (0 == nsize){return 0;}printf("RECV:%s\n", tmpbuff);sprintf(tmpbuff, "%s --- echo", tmpbuff);nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);if (-1 == nsize){return -1;}return nsize;
}int main(void)
{int sockfd = 0;int confd = 0;int ret = 0;fd_set rdfds;fd_set tmpfds;int nready = 0;int maxfd = 0;int i = 0;//创建监听套接字sockfd = CreateListenSocket(SER_IP, SER_PORT);if (-1 == sockfd){printf("创建监听套接字失败\n");return -1;}//将sockfd加入监听集合中FD_ZERO(&rdfds);FD_SET(sockfd, &rdfds);maxfd = sockfd;while (1){//开始监听tmpfds = rdfds;nready = select(maxfd+1, &tmpfds, NULL, NULL, NULL);if (-1 == nready){perror("fail to select");return -1;}//如果sockfd产生事件,处理新的连接请求,并将新的文件描述符加入集合,下次一起监听if (FD_ISSET(sockfd, &tmpfds)){confd = accept(sockfd, NULL, NULL);if (-1 == confd){FD_CLR(sockfd, &rdfds);close(sockfd);continue;}   maxfd = maxfd > confd ? maxfd : confd;FD_SET(confd, &rdfds);}//遍历所有已经连接的客户端中是否有事件发生for (i = sockfd+1; i <= maxfd; i++){if (FD_ISSET(i, &tmpfds)){ret = HandleConnection(i);if (-1 == ret){printf("连接异常\n");FD_CLR(i, &rdfds);close(i);continue;}else if (0 == ret){printf("连接断开\n");FD_CLR(i, &rdfds);close(i);continue;}}}}close(sockfd);return 0;
}

2.poll

3.epoll

 二、总结

        2024年8月20日,学习的第36天。今天主要学习TCP的并发模型,主要学习如何模拟实现现实中统一服务器可以和好多不同的客户端同时交互。

        加油!

这篇关于嵌入式学习Day36---Linux软件编程---网络编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1091914

相关文章

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Linux之systemV共享内存方式

《Linux之systemV共享内存方式》:本文主要介绍Linux之systemV共享内存方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、工作原理二、系统调用接口1、申请共享内存(一)key的获取(二)共享内存的申请2、将共享内存段连接到进程地址空间3、将

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Linux命令之firewalld的用法

《Linux命令之firewalld的用法》:本文主要介绍Linux命令之firewalld的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux命令之firewalld1、程序包2、启动firewalld3、配置文件4、firewalld规则定义的九大

Linux之计划任务和调度命令at/cron详解

《Linux之计划任务和调度命令at/cron详解》:本文主要介绍Linux之计划任务和调度命令at/cron的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux计划任务和调度命令at/cron一、计划任务二、命令{at}介绍三、命令语法及功能 :at

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Linux内核参数配置与验证详细指南

《Linux内核参数配置与验证详细指南》在Linux系统运维和性能优化中,内核参数(sysctl)的配置至关重要,本文主要来聊聊如何配置与验证这些Linux内核参数,希望对大家有一定的帮助... 目录1. 引言2. 内核参数的作用3. 如何设置内核参数3.1 临时设置(重启失效)3.2 永久设置(重启仍生效

kali linux 无法登录root的问题及解决方法

《kalilinux无法登录root的问题及解决方法》:本文主要介绍kalilinux无法登录root的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录kali linux 无法登录root1、问题描述1.1、本地登录root1.2、ssh远程登录root2、