当前位置:  编程技术>软件工程/软件设计
本页文章导读:
    ▪linux网络编程中select/poll/epoll的比较分析      一.select 1.概述 select本质是通过设置或检查存放fd标志位的数据结构来进行下一步的处理。会阻塞,直到有一个或多个I/O就绪。 监视的文件描述符分为三类set,每一种对应不同的事件。readfds、.........
    ▪C语言中自动变量栈的分配      大家都知道在c语言的运行过程中,局部变量都是存放在栈中的,且是从高位到低位进行进行空间分配。先看一个程序。很明显,地址从高到低分配,和预计的一样。稍微修改一下,再运行。.........
    ▪延时操作        tasklet例程 简单实现步骤1.DECLARE_TASKLET()  2. tasklet_schedule(&demo_tasklet); //设备相关的指针 static struct demo_dev *p = ....; //延迟操作函数 void demo_delay_action(unsigned long data) {    // 通过.........

[1]linux网络编程中select/poll/epoll的比较分析
    来源: 互联网  发布时间: 2013-11-19
一.select 1.概述

select本质是通过设置或检查存放fd标志位的数据结构来进行下一步的处理。会阻塞,直到有一个或多个I/O就绪。

监视的文件描述符分为三类set,每一种对应不同的事件。readfds、writefds和exceptfds是指向描述符集的指针。

readfds列出的文件描述符被监视是否有数据可供读取。(可读)

writefds列出的文件描述符被监视是否有写入操作完成。(可写)

exceptfds列出的文件描述符被监视是否发生异常,或无法控制的数据是否可用。(仅仅用于socket)

这三类set为NULL时,select()不监视其对应的该类事件。

select()成功返回时,每组set都被修改以使它只包含准备好的I/O描述符。

其缺点:(a)单个进程可监视的fd数量被限制;

(b)需要维护一个用来存放大量fd的数据结构,这样会使用户空间和内核空间在传递该结构时复制开销大;

(c)对fd进行扫描是线性的,fd剧增后,IO效率较低,因为每次调用都对fd进行线性扫描遍历,所以随着fd的增加会造成遍历速度慢的性能问题;

(d)内核需要将消息传递用户空间,需要内核拷贝动作;

(e)最大支持1024个fd。

2.实战

server端代码,文件名为:select-server.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>

#define MAXBUF 1024
/************关于本文档********************************************
*filename: select-server.c
*purpose: 演示网络异步通讯、select用法,这是服务器端程序
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to: Google.com
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*********************************************************************/

int main(int argc, char **argv)
{
    int sockfd, new_fd;
    socklen_t len;
    struct sockaddr_in my_addr, their_addr;
    unsigned int myport, lisnum;
    char buf[MAXBUF + 1];
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd = -1;

    if (argv[1])
        myport = atoi(argv[1]);
    else
        myport = 7838;

    if (argv[2])
        lisnum = atoi(argv[2]);
    else
        lisnum = 2;

    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = PF_INET;
    my_addr.sin_port = htons(myport);
    if (argv[3])
        my_addr.sin_addr.s_addr = inet_addr(argv[3]);
    else
        my_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
        == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(sockfd, lisnum) == -1) {
        perror("listen");
        exit(1);
    }

    while (1) {
        printf
            ("\n----等待新的连接到来开始新一轮聊天……\n");
        len = sizeof(struct sockaddr);
        if ((new_fd =
             accept(sockfd, (struct sockaddr *) &their_addr,
                    &len)) == -1) {
            perror("accept");
            exit(errno);
        } else
            printf("server: got connection from %s, port %d, socket %d\n",
                   inet_ntoa(their_addr.sin_addr),
                   ntohs(their_addr.sin_port), new_fd);

        /* 开始处理每个新连接上的数据收发 */
        printf
            ("\n准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方\n");
        while (1) {
            /* 把集合清空 */
            FD_ZERO(&rfds);
            /* 把标准输入(stdin)句柄0加入到集合中 */
            FD_SET(0, &rfds);
            maxfd = 0;
            /* 把当前连接(socket)句柄new_fd加入到集合中 */
            FD_SET(new_fd, &rfds);
            if (new_fd > maxfd)
                maxfd = new_fd;
            /* 设置最大等待时间 */
            tv.tv_sec = 1;
            tv.tv_usec = 0;
            /* 开始等待 */
            retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
            if (retval == -1) {
                printf("将退出,select出错! %s", strerror(errno));
                break;
            } else if (retval == 0) {
                /* printf
                   ("没有任何消息到来,用户也没有按键,继续等待……\n"); */
                continue;
            } else {
		        /*判断当前IO是否是stdin*/
                if (FD_ISSET(0, &rfds)) {
                    /* 用户按键了,则读取用户输入的内容发送出去 */
                    bzero(buf, MAXBUF + 1);
                    fgets(buf, MAXBUF, stdin);
                    if (!strncasecmp(buf, "quit", 4)) {
                        printf("自己请求终止聊天!\n");
                        break;
                    }
                    len = send(new_fd, buf, strlen(buf) - 1, 0);
                    if (len > 0)
                        printf
                            ("消息:%s\t发送成功,共发送了%d个字节!\n",
                             buf, len);
                    else {
                        printf
                            ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",
                             buf, errno, strerror(errno));
                        break;
                    }
                }
		        /*判断当前IO是否是来自socket*/
                if (FD_ISSET(new_fd, &rfds)) {
                    /* 当前连接的socket上有消息到来则接收对方发过来的消息并显示 */
                    bzero(buf, MAXBUF + 1);
                    /* 接收客户端的消息 */
                    len = recv(new_fd, buf, MAXBUF, 0);
                    if (len > 0)
                        printf
                            ("接收消息成功:'%s',共%d个字节的数据\n",
                             buf, len);
                    else {
                        if (len < 0)
                            printf
                                ("消息接收失败!错误代码是%d,错误信息是'%s'\n",
                                 errno, strerror(errno));
                        else
                            printf("对方退出了,聊天终止\n");
                        break;
                    }
                }
            }
        }
        close(new_fd);
        /* 处理每个新连接上的数据收发结束 */
        printf("还要和其它连接聊天吗?(no->退出)");
        fflush(stdout);
        bzero(buf, MAXBUF + 1);
        fgets(buf, MAXBUF, stdin);
        if (!strncasecmp(buf, "no", 2)) {
            printf("终止聊天!\n");
            break;
        }
    }

    close(sockfd);
    return 0;
}

client端代码,文件名为select-client.c

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>

#define MAXBUF 1024
/************关于本文档********************************************
// *filename: select-client.c
*purpose: 演示网络异步通讯,这是客户端程序
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to: Google.com
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*********************************************************************/
int main(int argc, char **argv)
{
    int sockfd, len;
    struct sockaddr_in dest;
    char buffer[MAXBUF + 1];
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd = -1;

    if (argc != 3) {
        printf
            ("参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",
             argv[0], argv[0]);
        exit(0);
    }
    /* 创建一个 socket 用于 tcp 通信 */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket");
        exit(errno);
    }

    /* 初始化服务器端(对方)的地址和端口信息 */
    bzero(&dest, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(atoi(argv[2]));
    if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {
        perror(argv[1]);
        exit(errno);
    }

    /* 连接服务器 */
    if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
        perror("Connect ");
        exit(errno);
    }

    printf
        ("\n准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方\n");
    while (1) {
        /* 把集合清空 */
        FD_ZERO(&rfds);
        /* 把标准输入句柄0加入到集合中 */
        FD_SET(0, &rfds);
        maxfd = 0;      
    
[2]C语言中自动变量栈的分配
    来源: 互联网  发布时间: 2013-11-19

大家都知道在c语言的运行过程中,局部变量都是存放在栈中的,且是从高位到低位进行进行空间分配。

先看一个程序。



很明显,地址从高到低分配,和预计的一样。

稍微修改一下,再运行。




很明显,从低位到高位!!!

明确一下问题:栈区会应为局部变量的占内存的大小更改内存的分配方式。

为什么?为什么?为什么?


用-S生成汇编语言看一下

第一种情况的汇编语言

	.file	"main.c"
	.section	.rodata
.LC0:
	.string	"Address s = Ox%x\n"
.LC1:
	.string	"Address d = Ox%x\n"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	andl	$-16, %esp
	subl	$32, %esp
	movl	%gs:20, %eax
	movl	%eax, 28(%esp)
	xorl	%eax, %eax
	movl	$6513249, 24(%esp)
	movw	$25185, 21(%esp)
	movb	$0, 23(%esp)
	leal	24(%esp), %eax
	movl	%eax, 4(%esp)
	movl	$.LC0, (%esp)
	call	printf
	leal	21(%esp), %eax
	movl	%eax, 4(%esp)
	movl	$.LC1, (%esp)
	call	printf
	movl	$1, %eax
	movl	28(%esp), %edx
	xorl	%gs:20, %edx
	je	.L3
	call	__stack_chk_fail
.L3:
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
	.section	.note.GNU-stack,"",@progbits

第二种情况的汇编语言

	.file	"main.c"
	.section	.rodata
.LC0:
	.string	"Address s = Ox%x\n"
.LC1:
	.string	"Address d = Ox%x\n"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	andl	$-16, %esp
	subl	$32, %esp
	movl	%gs:20, %eax
	movl	%eax, 28(%esp)
	xorl	%eax, %eax
	movl	$6513249, 17(%esp)
	movl	$1684234849, 21(%esp)
	movw	$26213, 25(%esp)
	movb	$0, 27(%esp)
	leal	17(%esp), %eax
	movl	%eax, 4(%esp)
	movl	$.LC0, (%esp)
	call	printf
	leal	21(%esp), %eax
	movl	%eax, 4(%esp)
	movl	$.LC1, (%esp)
	call	printf
	movl	$1, %eax
	movl	28(%esp), %edx
	xorl	%gs:20, %edx
	je	.L3
	call	__stack_chk_fail
.L3:
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
	.section	.note.GNU-stack,"",@progbits

在前面的几句mov有很明显的不同,一个是从低到高分配,一个是从高到低分配.


猜想:编译器对语言进行的优化,让长的字符串先进栈。


但为什么要这么做呢?

求解答。


本文转载自:http://blog.csdn.net/qp120291570/article/details/8889950


作者:DLUTBruceZhang 发表于2013-6-5 14:10:47 原文链接
阅读:0 评论:0 查看评论

    
[3]延时操作
    来源: 互联网  发布时间: 2013-11-19

 

tasklet例程

简单实现步骤1.DECLARE_TASKLET()  2. tasklet_schedule(&demo_tasklet);
//设备相关的指针
static struct demo_dev *p = ....;

//延迟操作函数
void demo_delay_action(unsigned long data)
{
   // 通过data获得设备相关指针
   static struct demo_dev * pdev = (static struct demo_dev *)data;
  // 延迟操作
  .....
}

//用DECLARE_TASKLET(name, func, data)定义一个tasklet对象demo_tasklet
DECLARE_TASKLET(demo_tasklet, demo_delay_action, (unsigned log)p );

//中断处理例程
irqreturn_t demo_isr(int irq, void * dev_id)
{
   .................
   通过tasklet_schedule实现延迟操作
    tasklet_schedule(&demo_tasklet);  //此处提交tasklet对象和SOFTIRQ部分调用处理
}

在任意时刻,同一tasklet只能有一个实例在运行,即使是多处理器系统也如此。tasklet另一个特性是:
那个处理器调用tasklet_schedule提交的tasklet,只能在该处理器上运行。


 

工作队列work queue

简单实现步骤:1. INIT_WORK(_work, _func);    2. schedule_work();

struct work_struct    //工作节点

struct cpu_workqueue_struct   //cpu工作队列管理结构

struct workqueue_struct  //工作队列管理管理结构

 

驱动程序可以调用create_singlethread_workaueue和creat_workqueue函数来让内核生成属于自己的工作队列,两者区别

前者只在系统中第一个CPU上创建工作队列和工人线程,后者函数会在系统中每个CPU上创建工作队列和工人线程。在用

queue_work提交工作节点时,如果是singlethread类型,只能提交到这唯一的一个worklist。反之,如果不是singlethread

类型,那么工作节点将会提交到当前运行queue_work的CPU所在的worklist中。

 

动态初始化:INIT_WORK(_work, _func)

静态初始化:DECLARE_WORK(n,f)

提交工作节点时只需调用schedule_work()函数就可以,对于queue_delayed_work,对于内核创建的工作队列而言,

延迟提交函数变成schedule_delayed_work().

 

使用内核工作队列好处是驱动无须创建自己的工作队列就可以提交节点来实现延迟操作,坏处是正在与系统

中其它模块共享一个工作队列以及该队列上的work_thread,所以无法预期提交一个节点需多久才调度执行。

 

内核提供了另一个提交节点的函数queue_delayed_work

int queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay);

 

自己创建工作队列例程:


//定义全局性的struct workqueue_struct指针demo_dev_wq
static struct workqueue_struct * demo_dev_wq;

//设备特定的数据结构,实际使用中大部分struct work_struct结构都内嵌在这个数据结构中
struct demo_device{
....................
struct work_struct work;
...............
}

static struct demo_device * demo_dev;

//定义延迟操作函数
void demo_work_func(ftruct work_struct *work)
{.................}

// 驱动程序模块初始化代码调用create_singlethread_workqueue创建工作队列
static int_init demo_dev_init(void)
{ ..................
  demo_dev = kzalloc(sizeof *demo_dev,GFP_KERNEL);

demo_dev_wq = create_singlethread_workqueue("demo_dev_workqueue");
INIT_WORK(&demo_dev->work,demo_work_func);
...................
}

//模块退出函数
static void demo_dev _exit(void)
{.................
   flush_wokqueue(demo_dev_wq);
  destroy_workqueue(demo_dev_wq);
.........................
}

//中断处理函数
irqreturn_t demo_isr(int irq, void * dev_id)
{...........................
   queue_work(demo_dev_wq, &demo_dev->work);
   ..........................
}

作者:jacobywu 发表于2013-6-4 17:15:38 原文链接
阅读:22 评论:0 查看评论

    
最新技术文章:
▪主-主数据库系统架构    ▪java.lang.UnsupportedClassVersionError: Bad version number i...    ▪eclipse项目出现红色叉叉解决方案
▪Play!framework 项目部署到Tomcat    ▪dedecms如何做中英文网站?    ▪Spring Batch Framework– introduction chapter(上)
▪第三章 AOP 基于@AspectJ的AOP    ▪基于插件的服务集成方式    ▪Online Coding开发模式 (通过在线配置实现一个表...
mysql iis7站长之家
▪机器学习理论与实战(二)决策树    ▪Hibernate(四)——全面解析一对多关联映射    ▪我所理解的设计模式(C++实现)——解释器模...
▪利用规则引擎打造轻量级的面向服务编程模式...    ▪google blink的设计计划: Out-of-Progress iframes    ▪FS SIP呼叫的消息线程和状态机线程
▪XML FREESWITCH APPLICATION 实现    ▪Drupal 实战    ▪Blink: Chromium的新渲染引擎
▪(十四)桥接模式详解(都市异能版)    ▪你不知道的Eclipse用法:使用Allocation tracker跟...    ▪Linux内核-进程
▪你不知道的Eclipse用法:使用Metrics 测量复杂度    ▪IT行业为什么没有进度    ▪Exchange Server 2010/2013三种不同的故障转移
▪第二章 IoC Spring自动扫描和管理Bean    ▪CMMI简介    ▪目标检测(Object Detection)原理与实现(六)
▪值班总结(1)——探讨sql语句的执行机制    ▪第二章 IoC Annotation注入    ▪CentOS 6.4下安装Vagrant
▪Java NIO框架Netty1简单发送接受    ▪漫画研发之八:会吃的孩子有奶吃    ▪比较ASP和ASP.NET
▪SPRING中的CONTEXTLOADERLISTENER    ▪在Nginx下对网站进行密码保护    ▪Hibernate从入门到精通(五)一对一单向关联映...
▪.NET领域驱动设计—初尝(三:穿过迷雾走向光...    ▪linux下的块设备驱动(一)    ▪Modem项目工作总结
▪工作流--JBPM简介及开发环境搭建    ▪工作流--JBPM核心服务及表结构    ▪Eclipse:使用JDepend 进行依赖项检查
▪windows下用putty上传文件到远程Linux方法    ▪iBatis和Hibernate的5点区别    ▪基于学习的Indexing算法
▪设计模式11---设计模式之中介者模式(Mediator...    ▪带你走进EJB--JMS编程模型    ▪从抽象谈起(二):观察者模式与回调
▪设计模式09---设计模式之生成器模式(Builder)也...    ▪svn_resin_持续优化中    ▪Bitmap recycle方法与制作Bitmap的内存缓存
▪Hibernate从入门到精通(四)基本映射    ▪设计模式10---设计模式之原型模式(Prototype)    ▪Dreamer 3.0 支持json、xml、文件上传
▪Eclipse:使用PMD预先检测错误    ▪Jspx.net Framework 5.1 发布    ▪从抽象谈起(一):工厂模式与策略模式
▪Eclipse:使用CheckStyle实施编码标准    ▪【论文阅读】《Chain Replication for Supporting High T...    ▪Struts2 Path_路径问题
▪spring 配置文件详解    ▪Struts2第一个工程helloStruts极其基本配置    ▪Python学习入门基础教程(learning Python)--2 Python简...
▪maven springmvc环境配置    ▪基于SCRUM的金融软件开发项目    ▪software quality assurance 常见问题收录
▪Redis集群明细文档    ▪Dreamer 框架 比Struts2 更加灵活    ▪Maven POM入门
▪git 分支篇-----不断更新中    ▪Oracle非主键自增长    ▪php设计模式——UML类图
▪Matlab,Visio等生成的图片的字体嵌入问题解决...    ▪用Darwin和live555实现的直播框架    ▪学习ORM框架—hibernate(二):由hibernate接口谈...
▪(十)装饰器模式详解(与IO不解的情缘)    ▪无锁编程:最简单例子    ▪【虚拟化实战】网络设计之四Teaming
▪OSGi:生命周期层    ▪Javascript/Jquery——简单定时器    ▪java代码 发送GET、POST请求
▪Entity Framework底层操作封装(3)    ▪HttpClient 发送GET、POST请求    ▪使用spring框架,应用启动时,加载数据
▪Linux下Apache网站目录读写权限的设置    ▪单键模式的C++描述    ▪学习ORM框架—hibernate(一):初识hibernate
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3