锁定老帖子 主题:关于NIO中异步读写的实践讨论
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-04-19
CshBBrain 写道 如果你只关心无法区分接收数据的链接和发送数据的连接是否为同一个连接的话,这个问题应该好弄;创建连接的时候创建一个标识连接的对象,然后把这个对象通过 SelectionKey 的这个方法 attach(obj)附带在SelectionKey 中,发送数据时调用attch()方法就可以取到创建连接时所创建的标识连接的对象了。用NIO来写好一个非阻塞式的服务器所面临的问题远不止这个......
恩,我关心的是怎么把异步的技术用于实践,因为我的需求过程,打个比方 ---------------isReadable--------- request 1 request 2 读取两个请求并且计算响应response 1, response 2 ---------------isWriteable-------- 按照读写异步,这时是另外一个线程了,那么这个线程要去取读线程(或者说可能是来自独立的计算线程的结果),然后再发送,那么取结果的时候就需要判断这个结果是1还是2 通过附加标示符是可以解决问题,请问有没有示例的代码呢 |
|
返回顶楼 | |
发表时间:2012-04-19
baiweiyll 写道 NIO是非阻塞,但和异步IO还是不一样的。jdk7已经引入了异步IO(AIO),可以看一下。
你说那个连接状态是为了连接复用吗?,如果服务端返回的响应能带上请求标识,那么客服端则可采用连接复用的方式,即每个SocketChannel在发送消息后,不用等响应即可继续发送其他消息。 恩,我知道NIO是非阻塞,我的问题就是由于非阻塞带来的读写异步的具体实现的问题 |
|
返回顶楼 | |
发表时间:2012-04-19
须等待 写道 baiweiyll 写道 NIO是非阻塞,但和异步IO还是不一样的。jdk7已经引入了异步IO(AIO),可以看一下。
你说那个连接状态是为了连接复用吗?,如果服务端返回的响应能带上请求标识,那么客服端则可采用连接复用的方式,即每个SocketChannel在发送消息后,不用等响应即可继续发送其他消息。 恩,我知道NIO是非阻塞,我的问题就是由于非阻塞带来的读写异步的具体实现的问题 NIO也可以写成阻塞的 |
|
返回顶楼 | |
发表时间:2012-04-19
须等待 写道
CshBBrain 写道
如果你只关心无法区分接收数据的链接和发送数据的连接是否为同一个连接的话,这个问题应该好弄;创建连接的时候创建一个标识连接的对象,然后把这个对象通过 SelectionKey 的这个方法 attach(obj)附带在SelectionKey 中,发送数据时调用attch()方法就可以取到创建连接时所创建的标识连接的对象了。用NIO来写好一个非阻塞式的服务器所面临的问题远不止这个......
恩,我关心的是怎么把异步的技术用于实践,因为我的需求过程,打个比方 ---------------isReadable--------- request 1 request 2 读取两个请求并且计算响应response 1, response 2 ---------------isWriteable-------- 按照读写异步,这时是另外一个线程了,那么这个线程要去取读线程(或者说可能是来自独立的计算线程的结果),然后再发送,那么取结果的时候就需要判断这个结果是1还是2 通过附加标示符是可以解决问题,请问有没有示例的代码呢
|
|
返回顶楼 | |
发表时间:2012-04-19
置个标记,request带个自增id,response里面也带上这个id。或者做个Map容器,request之前记下key,null,异步返回完成是把response写进去。取结果从容器里取。
|
|
返回顶楼 | |
发表时间:2012-04-19
按照LZ的描述
应该是一个连接多次请求,返回响应的顺序问题吧。 跟NIO没什么关系,普通的socket用多线程处理iostream读到的多个包,也有这个问题啊。 这是业务层面的事情。 看业务场景。如果要求先发生的请求先处理先返回,那就用队列处理。 如果是先发送的请求可以后响应,那就统一由客户端自己去判断是哪次的请求。 比如聊天的业务场景: A给自己发消息,这个只能用队列处理,不可能A后发的一条消息服务端先转发给A自己了,那就乱套了。 如果A给自己发条消息后又同时给服务端上传了自己的头像。这时候服务器可以先更新A的头像再返回A的消息,本身协议不一样,客户端自然知道如何区分。 搞不懂这个跟key附加的标识对象有什么关系,一个客户端线程跟服务端就只有一个通道,多线程客户端跟服务端那就是不同通道,本来就是不同的channel。 难道是有了结果不知道是哪个channel?channel是当做参数传入读写线程的啊,不可能不知道啊。 |
|
返回顶楼 | |
发表时间:2012-04-19
CshBBrain 写道
须等待 写道
CshBBrain 写道
如果你只关心无法区分接收数据的链接和发送数据的连接是否为同一个连接的话,这个问题应该好弄;创建连接的时候创建一个标识连接的对象,然后把这个对象通过 SelectionKey 的这个方法 attach(obj)附带在SelectionKey 中,发送数据时调用attch()方法就可以取到创建连接时所创建的标识连接的对象了。用NIO来写好一个非阻塞式的服务器所面临的问题远不止这个......
恩,我关心的是怎么把异步的技术用于实践,因为我的需求过程,打个比方 ---------------isReadable--------- request 1 request 2 读取两个请求并且计算响应response 1, response 2 ---------------isWriteable-------- 按照读写异步,这时是另外一个线程了,那么这个线程要去取读线程(或者说可能是来自独立的计算线程的结果),然后再发送,那么取结果的时候就需要判断这个结果是1还是2 通过附加标示符是可以解决问题,请问有没有示例的代码呢
太棒了,如果我理解的没有问题,每个SelectionKey是对应的一个链接对吧? |
|
返回顶楼 | |
发表时间:2012-04-19
aronlulu 写道 按照LZ的描述
应该是一个连接多次请求,返回响应的顺序问题吧。 跟NIO没什么关系,普通的socket用多线程处理iostream读到的多个包,也有这个问题啊。 这是业务层面的事情。 看业务场景。如果要求先发生的请求先处理先返回,那就用队列处理。 如果是先发送的请求可以后响应,那就统一由客户端自己去判断是哪次的请求。 比如聊天的业务场景: A给自己发消息,这个只能用队列处理,不可能A后发的一条消息服务端先转发给A自己了,那就乱套了。 如果A给自己发条消息后又同时给服务端上传了自己的头像。这时候服务器可以先更新A的头像再返回A的消息,本身协议不一样,客户端自然知道如何区分。 搞不懂这个跟key附加的标识对象有什么关系,一个客户端线程跟服务端就只有一个通道,多线程客户端跟服务端那就是不同通道,本来就是不同的channel。 难道是有了结果不知道是哪个channel?channel是当做参数传入读写线程的啊,不可能不知道啊。 其中有返回顺序的问题,但是更多的问题是来自并发时如果标识不同的response的问题 |
|
返回顶楼 | |
发表时间:2012-04-19
最后修改:2012-04-19
干嘛要标识不同的response?一个连接就是一个channel,channel始终是读写线程的成员变量。并发时无非就是N多个channel而已。channel有了直接回写response不就行了。
标识符一般是用来传递这个连接的包装信息的。如BufferSize,TrafficClass等。 还有上面的程序都是阻塞程序,三个if分支任何一个堵塞了就玩不起来了。 if (key.isWritable()) { if (iter.hasNext()) { server.submit(new WriteTask(iter.next(), channel)); channel.register(selector, SelectionKey.OP_READ); } else { break; } Thread.sleep(50); } if (key.isReadable()) { server.submit(new ReadTask(channel)); channel.register(selector, SelectionKey.OP_WRITE); } |
|
返回顶楼 | |
发表时间:2012-04-19
aronlulu 写道 干嘛要标识不同的response?一个连接就是一个channel,channel始终是读写线程的成员变量。并发时无非就是N多个channel而已。channel有了直接回写response不就行了。
标识符一般是用来传递这个连接的包装信息的。如BufferSize,TrafficClass等。 还有上面的程序都是阻塞程序,三个if分支任何一个堵塞了就玩不起来了。 if (key.isWritable()) { if (iter.hasNext()) { server.submit(new WriteTask(iter.next(), channel)); channel.register(selector, SelectionKey.OP_READ); } else { break; } Thread.sleep(50); } if (key.isReadable()) { server.submit(new ReadTask(channel)); channel.register(selector, SelectionKey.OP_WRITE); } 因为服务器是并发的环境,同时会有很多个channel,要返回不同的response,不区分的话怎么分别返回呢 |
|
返回顶楼 | |