将poll程序改为epoll实现

原实例在APUE(第三版)17.2 UNIX域套接字

1、使用UNIX与套接字轮询XSI消息队列(poll版,原版)

#include "apue.h"
#include <poll.h>
#include <pthread.h>
#include <sys/msg.h>
#include <sys/socket.h>

#define NQ			3		//队列的数量
#define MAXMSZ		512		//消息的最大长度
#define KEY			0x123	//消息队列的第一个key值

struct threadinfo {
	int qid;
	int fd;
};

struct mymesg {
	long mtype;
	char mtext[MAXMSZ];
};

void *helper(void *arg)
{
	int n;
	struct mymesg m;
	struct threadinfo *tip = arg;

	for (;;) {
		printf("helper qid %d, fd %d, tid %u\n", tip->qid, tip->fd, (unsigned)pthread_self());

		memset(&m, 0, sizeof(m));
		if ((n = msgrcv(tip->qid, &m, MAXMSZ, 0, MSG_NOERROR)) < 0) {
			err_sys("msgrcv error");
		}
		if (write(tip->fd, m.mtext, n) < 0) {
			err_sys("write error");
		}
	}
}
int main()
{
	int i, n, err;
	int fd[2];
	int qid[NQ];
	struct pollfd pfd[NQ];
	struct threadinfo ti[NQ];
	pthread_t tid[NQ];
	char buf[MAXMSZ];

	for (i = 0; i < NQ; ++i) {
		if ((qid[i] = msgget((KEY+i), IPC_CREAT|0666)) < 0) {	//创建一个新队列
			err_sys("msgget error");
		}
		printf("queue %d ID is %d\n", i, qid[i]);
		if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fd) < 0) {	//创建UNXI域套接字(fd管道)
			err_sys("socketpair error");
		}
		printf("fd[0]:%d\n", fd[0]);
		printf("fd[1]:%d\n", fd[1]);
		pfd[i].fd = fd[0];
		pfd[i].events = POLLIN;
		ti[i].qid = qid[i];
		ti[i].fd = fd[1];
		if ((err = pthread_create(&tid[i], NULL, helper, &ti[i])) != 0) {	//创建线程
			err_exit(err, "pthread_create error");
		}
	}

	for (;;) {
		if (poll(pfd, NQ, -1) < 0) {	//等待事件发生
			err_sys("poll error");
		}
		for (i = 0; i < NQ; ++i) {
			//printf("i:%d\n", i);
			if (pfd[i].revents & POLLIN) {
				if ((n = read(pfd[i].fd, buf, sizeof(buf))) < 0) {
					err_sys("read error");
				}
				buf[n] = 0;
				printf("queue %d id %d, message %s\n", i, qid[i], buf);
			}
		}
	}
	exit(0);
}

编译命令:

gcc pollmsg.c -o pollmsg -lapue -lpthread -std=c99

2、使用UNIX与套接字轮询XSI消息队列(epoll版,改版)

#include "apue.h"
#include <pthread.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <sys/epoll.h>

#define NQ			3		//队列的数量
#define MAXMSZ		512		//消息的最大长度
#define KEY			0x123	//消息队列的第一个key值
#define FDSIZE		1000
#define EPOLLEVENTS	100

struct threadinfo {
	int qid;
	int fd;
};

struct mymesg {
	long mtype;
	char mtext[MAXMSZ];
};

void *helper(void *arg)
{
	int n;
	struct mymesg m;
	struct threadinfo *tip = arg;

	for (;;) {
		printf("helper qid %d, fd %d, tid %u\n", tip->qid, tip->fd, (unsigned)pthread_self());

		memset(&m, 0, sizeof(m));
		if ((n = msgrcv(tip->qid, &m, MAXMSZ, 0, MSG_NOERROR)) < 0) {
			err_sys("msgrcv error");
		}
		if (write(tip->fd, m.mtext, n) < 0) {
			err_sys("write error");
		}
	}
}

int main()
{
	int i, n, err;
	int fd[2];
	int qid[NQ];
	int epollfd;
	struct epoll_event events[EPOLLEVENTS];
	struct threadinfo ti[NQ];
	pthread_t tid[NQ];
	char buf[MAXMSZ];

	epollfd = epoll_create(FDSIZE);	//创建epoll文件描述符

	for (i = 0; i < NQ; ++i) {
		if ((qid[i] = msgget((KEY+i), IPC_CREAT|0666)) < 0) {	//创建一个新队列
			err_sys("msgget error");
		}
		printf("queue %d ID is %d\n", i, qid[i]);
		if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fd) < 0) {	//创建UNXI域套接字(fd管道)
			err_sys("socketpair error");
		}
		struct epoll_event ev;
		ev.events = EPOLLIN;
		ev.data.fd = fd[0];
		epoll_ctl(epollfd, EPOLL_CTL_ADD, fd[0], &ev);	//注册fd[0]到epoll
		ti[i].qid = qid[i];
		ti[i].fd = fd[1];
		if ((err = pthread_create(&tid[i], NULL, helper, &ti[i])) != 0) {	//创建线程
			err_exit(err, "pthread_create error");
		}
	}

	for (;;) {
		int occurred;
		if ((occurred = epoll_wait(epollfd, events, EPOLLEVENTS, -1)) < 0) {	//等待事件发生
			err_sys("epoll error");
		}
		if (occurred == 0) {
			err_sys("epoll timeout");
		}

		for (i = 0; i < occurred; ++i) {
			if (events[i].events & EPOLLIN) {
				if ((n = read(events[i].data.fd, buf, sizeof(buf))) < 0) {
					err_sys("read error");
				}
				buf[n] = 0;
				printf("main thread %u, message %s\n", (unsigned)pthread_self(), buf);
			}
		}

	}
	exit(0);
}

编译命令:

gcc epollmsg.c -o epollmsg -lapue -lpthread -std=c99

3、给XSI消息队列发送消息(测试程序,原版)

#include "apue.h"
#include <sys/msg.h>

#define MAXMSZ 512

struct mymesg {
	long mtype;
	char mtext[MAXMSZ];
};

int main(int argc, char *argv[])
{
	key_t key;
	long qid;
	size_t nbytes;
	struct mymesg m;

	if (argc != 3) {
		fprintf(stderr, "usage: sendmsg KEY message\n");
		exit(1);
	}

	key = strtol(argv[1], NULL, 0);
	//printf("key:0x%08X\n", (unsigned )key);
	if ((qid = msgget(key, 0)) < 0) {	//打开一个现有队列
		err_sys("can‘t open queue key %s", argv[1]);
	}
	memset(&m, 0, sizeof(m));
	strncpy(m.mtext, argv[2], MAXMSZ - 1);
	nbytes = strlen(m.mtext);
	m.mtype = 1;
	//printf("qid:%ld\n", qid);
	if (msgsnd(qid, &m, nbytes, 0) < 0) {	//发送消息给指定消息队列
		err_sys("can‘t send message");
	}
	exit(0);
}

编译命令:

gcc sendmsg.c -o sendmsg -lapue -std=c99

相关阅读:

1、select、poll、epoll之间的区别总结[整理]

2、poll函数的使用原文

3、APUE读书笔记

*** walker ***

时间: 2024-10-10 01:58:59

将poll程序改为epoll实现的相关文章

socket编程之 select、poll、kqueue、epoll

原生API select int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 函数参数 numfds:文件描述符的最大值+1(为了限制检测文件描述符的范围) readfds:包含所有因为状态变为可读而触发select函数返回文件描述符 writefds:包含所有因为状态变为可写而触发select函数返回文件描述符 exceptfds:包含所有因

EasyDarwin开源流媒体server将select改为epoll的方法

本文来自EasyDarwin团队Fantasy(fantasy(at)easydarwin.org) 一. EasyDarwin网络模型介绍 EventContext负责监听全部网络读写事件.EventContext::RequestEvent每次插入一个监听事件到 监听列表(select 文件描写叙述符集合),EventThread::Entry()死循环监听加入到该FD_SET的全部文件描写叙述符的 事件.Entry()->select_waitevent()每次返回下一个要处理的事件节点,

小程序--改变子级别页面导航栏信息 / navigationBarTitleText

微信小程序在公共文件app.json中设置了导航栏相关样式如下: 其中  navigationBarTitleText 为设置导航栏名称,若是想子级页面和父页面的header页面不同,则在子级文件中新建一个配置文件.json 中配置 { "navigationBarTitleText": "新闻页面"} 这样在进入子级文件中便可以引用自身json文件的导航栏标题了

四则运算程序扩展:将程序改为java语言,并允许用户输入,对输入结果进行验证

题目 每个同学选一个方向,把程序扩展一下:1.让程序能接受用户输入答案,并判定对错.最后给出总共对/错 的数量.2.把程序变成一个网页程序,用户通过设定参数,就可以得到各种题目.3.把程序变成一个Windows 图形界面的程序.4.把程序变成一个智能手机程序 (你正在用什么手机, 就写那个手机的程序).(可以延期3周后)5.选一个你从来没有学过的编程语言,试一试实现基本功能. 设计思想 本次程序采用数组记录答案,包含输入数组和正确结果保存数组,进行比较 源代码 package minirisof

service程序改为windows窗体展示

首先将exe程序文件进行快捷创建.然后就会生成一个 exe -shortCut 程序,然后进入属性中,并且进行修改引用路径,在路径xx.exe 后面加一个空格和/tt,保存,这样就可以正常运行了. 如图 原文地址:https://www.cnblogs.com/Jack-S-Wang/p/11156597.html

IO多路复用(二) -- select、poll、epoll实现TCP反射程序

接着上文IO多路复用(一)-- Select.Poll.Epoll,接下来将演示一个TCP回射程序,源代码来自于该博文https://www.cnblogs.com/Anker/p/3258674.html 博主的几篇相关的文章,在这里将其进行了整合,突出select.poll和epoll不同方法之间的比较,但是代码的结构相同,为了突出方法之间的差别,可能有的代码改动的并不合理,实际中使用并非这么写. 程序逻辑 该程序的主要逻辑如下: 服务器: 1. 开启服务器套接字 2. 将服务器套接字加入要

epoll/poll/select的原理

随着2.6内核对epoll的完全支持,网络上很多的文章和示例代码都提供了这样一个信息:使用epoll代替传统的poll能给网络服务应用带来性能上的提升.但大多文章里关于性能提升的原因解释的较少,这里我将试分析一下内核(2.6.21.1)代码中poll与epoll的工作原理,然后再通过一些测试数据来对比具体效果.       POLL: 先说poll,poll或select为大部分Unix/Linux程序员所熟悉,这俩个东西原理类似,性能上也不存在明显差异,但select对所监控的文件描述符数量有

select、poll、epoll之间的区别总结[整理]

select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作.但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间.关于这三种IO多路复用的用法,前面三篇总结写的很清楚,并用服务器回射echo程序进行了测试.

select、poll、epoll之间的区别总结[转]

  原文链接:http://www.cnblogs.com/Anker/p/3265058.html select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作.但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到