互联网络程序设计实验-实验4(2)

2019-03-29 12:00

Epoll模型主要负责对大量并发用户的请求进行及时处理,完成服务器与客户端的数据交互。其具体的实现步骤如下:

(a) 使用epoll_create()函数创建文件描述,设定将可管理的最大socket描述符数目。

(b) 创建与epoll关联的接收线程,应用程序可以创建多个接收线程来处理epoll上的读通知事件,线程的数量依赖于程序的具体需要。 (c) 创建一个侦听socket描述符ListenSock;将该描述符设定为非阻塞模式,

调用Listen()函数在套接字上侦听有无新的连接请求,在 epoll_event结构中设置要处理的事件类型EPOLLIN,工作方式为 epoll_ET,以提高工作效率,同时使用epoll_ctl()注册事件,最后启动网络监视线程。

(d) 网络监视线程启动循环,epoll_wait()等待epoll事件发生。 (e) 如果epoll事件表明有新的连接请求,则调用accept()函数,将用户socket

描述符添加到epoll_data联合体,同时设定该描述符为非 阻塞,并在epoll_event结构中设置要处理的事件类型为读和写,工作方式为epoll_ET.

(f) 如果epoll事件表明socket描述符上有数据可读,则将该socket描述符加

入可读队列,通知接收线程读入数据,并将接收到的数据放入到接收数据 的链表中,经逻辑处理后,将反馈的数据包放入到发送数据链表中,等待由发送线程

发送。

? Reactor模式

1.Reactor 负责响应IO事件,一旦发生,广播发送给相应的Handler去处理,这类似于AWT的thread。

2.Handler 是负责非堵塞行为,类似于AWT ActionListeners;同时负责将handlers与event事件绑定,类似于AWT addActionListener如图:

Java的NIO为reactor模式提供了实现的基础机制,它的Selector当发现某个channel有数据时,会通过SlectorKey来告知我们,在此我们实现事件和handler的绑定。代码如下:

public class Reactor implements Runnable{ final Selector selector;

final ServerSocketChannel serverSocket; Reactor(int port) throws IOException { selector = Selector.open();

serverSocket = ServerSocketChannel.open(); InetSocketAddress address = new

InetSocketAddress(InetAddress.getLocalHost(),port); serverSocket.socket().bind(address);

serverSocket.configureBlocking(false); //向selector注册该channel

SelectionKey sk =serverSocket.register(selector,SelectionKey.OP_ACCEPT);

logger.debug(\

//利用sk的attache功能绑定Acceptor 如果有事情,触发Acceptor

sk.attach(new Acceptor());

logger.debug(\ }

public void run() { // normally in a new Thread try {

while (!Thread.interrupted()) {

selector.select();

Set selected = selector.selectedKeys(); Iterator it = selected.iterator();

//Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。

while (it.hasNext())

//来一个事件 第一次触发一个accepter线程 //以后触发SocketReadHandler dispatch((SelectionKey)(it.next())); selected.clear(); }

}catch (IOException ex) {

logger.debug(\ } }

//运行Acceptor或SocketReadHandler void dispatch(SelectionKey k) {

Runnable r = (Runnable)(k.attachment()); if (r != null){ // r.run(); } } }

以上代码中巧妙使用了SocketChannel的attach功能,将Hanlder和可能会发生事件的channel链接在一起,当发生事件时,可以立即触发相应链接的Handler。再看看Handler代码:

public class SocketReadHandler implements Runnable {

public static Logger logger = Logger.getLogger(SocketReadHandler.class); private Test test=new Test(); final SocketChannel socket; final SelectionKey sk;

static final int READING = 0, SENDING = 1; int state = READING;

public SocketReadHandler(Selector sel, SocketChannel c) throws IOException { socket = c;

socket.configureBlocking(false); sk = socket.register(sel, 0);

//将SelectionKey绑定为本Handler 下一步有事件触发时,将调用本类的run方法。

//参看dispatch(SelectionKey k) sk.attach(this);

//同时将SelectionKey标记为可读,以便读取。 sk.interestOps(SelectionKey.OP_READ); sel.wakeup(); }

public void run() { try{

// test.read(socket,input); readRequest() ; }catch(Exception ex){

logger.debug(\ } }

在Handler里面又执行了一次attach,这样,覆盖前面的Acceptor,下次该Handler又有READ事件发生时,将直接触发Handler.从而开始了数据的读 处理 写 发出等流程处理。

四、实验心得及体会

1.epoll的操作简单,总共不过4个API:epoll_create, epoll_ctl, epoll_wait和close。

2.使用linux的epoll模式的水平触发需要向 socket 写数据的时候才

把 socket 加入 epoll ,等待可写事件。接受到可写事件后,调用 write 或者 send 发送数据。当所有数据都写完后,把 socket 移出 epoll。

3.reactor类在做多路分离时需要操纵Event_Handler类的Handle,因此Event_Handler类需要提供get_handle()函数。

4.程序不需要再对特定事件响应时,需要把Event_Handler对象从事件

驱动列表中删除,因此reactor类还实现了remove_handler函数。reactor类内部提供一个事件循环:handle_events(),事件循环的代码实现利用了操作系统提供的多路分离函数,WaitForMultipleObjects或者select等,这些多路分离的函数的特点是,可以同时等待多个句柄,在等待过程中所在线程属于挂起状态,不消耗CPU时间,一旦某个句柄被触发,则线程被唤醒,函数将返回,线程可以执行后面的代码,利用多路分离函数的这一特点,根据被激活的句柄对应的特定事件,调用相关的事件处理函数。可以实现事件循环。


互联网络程序设计实验-实验4(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:复摆振动研究实验论文周久龙(0102)

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: