Java异步套接字实例
服务端
package com.test.server; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Set; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.*; import java.nio.*; import java.nio.channels.*; class AsynServer { static private int BUFFER_SIZE = 256; //定义一个临时的socket SocketChannel sc; public void start() { try { //定义一个事件选择器对象记录套接字通道的事件 Selector selector = Selector.open(); //定义一个异步服务器socket对象 ServerSocketChannel ssc = ServerSocketChannel.open(); //将此socket对象设置为异步 ssc.configureBlocking(false); //定义服务器socket对象-用来指定异步socket的监听端口等信息 ServerSocket ss = ssc.socket(); //定义存放监听端口的对象 InetSocketAddress address = new InetSocketAddress(55555); //将服务器与这个端口绑定 ss.bind(address); //将异步的服务器socket对象的接受客户端连接事件注册到selector对象内 ssc.register(selector, SelectionKey.OP_ACCEPT); System.out.println("服务端端口注册完毕!"); //通过此循环来遍例事件 while(true) { //查询事件如果一个事件都没有就阻塞 selector.select(); //定义一个byte缓冲区来存储收发的数据 ByteBuffer echoBuffer = ByteBuffer.allocate(BUFFER_SIZE); //此循环遍例所有产生的事件 for (SelectionKey key : selector.selectedKeys()) { //如果产生的事件为接受客户端连接(当有客户端连接服务器的时候产生) if((key.readyOps() & SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT) { selector.selectedKeys().remove(key); //定义一个服务器socket通道 ServerSocketChannel subssc = (ServerSocketChannel)key.channel(); //将临时socket对象实例化为接收到的客户端的socket sc = subssc.accept(); //将客户端的socket设置为异步 sc.configureBlocking(false); //将客户端的socket的读取事件注册到事件选择器中 sc.register(selector, SelectionKey.OP_READ); //将本此事件从迭带器中删除 System.out.println("服务端有新连接:" + sc); } //如果产生的事件为读取数据(当已连接的客户端向服务器发送数据的时候产生) else if((key.readyOps()&SelectionKey.OP_READ)==SelectionKey.OP_READ) { //将本次事件删除 selector.selectedKeys().remove(key); //临时socket对象实例化为产生本事件的socket sc = (SocketChannel) key.channel(); //定义一个用于存储byte数据的流对象 ByteArrayOutputStream bos = new ByteArrayOutputStream(); //先将客户端的数据清空 echoBuffer.clear(); //a为读取到数据的长度 try { //循环读取所有客户端数据到byte缓冲区中,当有数据的时候read函数返回数据长度 //NIO会自动的将缓冲区一次容纳不下的自动分段 int readInt = 0; while ((readInt = sc.read(echoBuffer)) > 0) { //如果获得数据长度比缓冲区大小小的话 if (readInt<echoBuffer.capacity()) { //建立一个临时byte数组,将齐长度设为获取的数据的长度 byte[] readByte=new byte[readInt]; //循环向此临时数组中添加数据 for(int i=0;i<readInt;i++) { readByte[i]=echoBuffer.get(i); } //将此数据存入byte流中 bos.write(readByte); } //否则就是获得数据长度等于缓冲区大小 else { //将读取到的数据写入到byte流对象中 bos.write(echoBuffer.array()); } //将缓冲区清空,以便进行下一次存储数据 echoBuffer.clear(); } //当循环结束时byte流中已经存储了客户端发送的所有byte数据 System.out.println("服务端接收数据: "+new String(bos.toByteArray())); } catch(Exception e) { //当客户端在读取数据操作执行之前断开连接会产生异常信息 e.printStackTrace(); //将本socket的事件在选择器中删除 key.cancel(); break; } //获取byte流对象的标准byte对象 //byte[] b=bos.toByteArray(); String resp = "server data"; byte[] b = resp.getBytes(); //建立这个byte对象的ByteBuffer,并将数据存入 ByteBuffer byteBuffer = ByteBuffer.allocate(b.length); byteBuffer.put(b); //向客户端写入收到的数据 Write(byteBuffer); //关闭客户端连接 sc.close(); //将本socket的事件在选择器中删除 key.cancel(); System.out.println("服务端连接结束"); System.out.println("============================="); } } } } catch (Exception e) { e.printStackTrace(); } } public boolean Write(ByteBuffer echoBuffer) { //将缓冲区复位以便于进行其他读写操作 echoBuffer.flip(); try { //向客户端写入数据,数据为接受到数据 sc.write(echoBuffer); } catch (IOException e) { e.printStackTrace(); return false; } System.out.println("服务端返回数据: "+new String(echoBuffer.array())); return true; } } public class TestServer { public static void main(String args[]) { new AsynServer().start(); } }
客户端
package com.test.client; import java.io.ByteArrayOutputStream; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; class AsynClient { static private int BUFFER_SIZE = 256; public void start() { try { //定义一个记录套接字通道事件的对象 Selector selector = Selector.open(); //定义一个服务器地址的对象 SocketAddress address = new InetSocketAddress("localhost", 55555); //定义异步客户端 SocketChannel client = SocketChannel.open(address); //将客户端设定为异步 client.configureBlocking(false); //在轮讯对象中注册此客户端的读取事件(就是当服务器向此客户端发送数据的时候) client.register(selector, SelectionKey.OP_READ); //要发送的数据 String content = "client data"; byte[] sendBytes = content.getBytes(); //定义用来存储发送数据的byte缓冲区 ByteBuffer sendbuffer = ByteBuffer.allocate(sendBytes.length); //定义用于接收服务器返回的数据的缓冲区 ByteBuffer readBuffer = ByteBuffer.allocate(BUFFER_SIZE); //将数据put进缓冲区 sendbuffer.put(sendBytes); //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位 sendbuffer.flip(); //向服务器发送数据 client.write(sendbuffer); System.out.println("客户端发送数据: " + new String(sendbuffer.array())); //利用循环来读取服务器发回的数据 while (true) { //如果客户端连接没有打开就退出循环 if (!client.isOpen()) break; //此方法为查询是否有事件发生如果没有就阻塞,有的话返回事件数量 int shijian = selector.select(); //如果没有事件返回循环 if (shijian==0) { continue; } //定义一个临时的客户端socket对象 SocketChannel sc; //遍例所有的事件 for (SelectionKey key : selector.selectedKeys()) { //删除本次事件 selector.selectedKeys().remove(key); //如果本事件的类型为read时,表示服务器向本客户端发送了数据 if (key.isReadable()) { //将临时客户端对象实例为本事件的socket对象 sc = (SocketChannel) key.channel(); //定义一个用于存储所有服务器发送过来的数据 ByteArrayOutputStream bos = new ByteArrayOutputStream(); //将缓冲区清空以备下次读取 readBuffer.clear(); int readInt = 0; //此循环从本事件的客户端对象读取服务器发送来的数据到缓冲区中 while ((readInt = sc.read(readBuffer)) > 0) { if (readInt<readBuffer.capacity()) { //建立一个临时byte数组,将齐长度设为获取的数据的长度 byte[] readByte=new byte[readInt]; //循环向此临时数组中添加数据 for(int i=0;i<readInt;i++) { readByte[i]=readBuffer.get(i); } //将此数据存入byte流中 bos.write(readByte); } //将缓冲区清空以备下次读取 readBuffer.clear(); } //如果byte流中存有数据 if (bos.size() > 0) { //建立一个普通字节数组存取缓冲区的数据 byte[] recvBytes = bos.toByteArray(); System.out.println("客户端接收数据: " + new String(recvBytes)); //关闭客户端连接,此时服务器在read读取客户端信息的时候会返回-1 client.close(); System.out.println("客户端连接关闭!"); } } } } } catch(Exception e) { e.printStackTrace(); } } } public class TestClient { public static void main(String args[]) { new AsynbClient().start(); } }
Java异步套接字实例的更多相关文章
- 孙鑫MFC学习笔记16:异步套接字
16 1.事件对象 2.CreateEvent创建事件对象 3.SetEvent设置事件对象为通知状态 4.ResetEvent设置事件对象为非通知状态 5.InitializeCriticalSec ...
- VC基于消息的异步套接字
用WSAStartup,需要在StdAfx.h头文件中需要声明 #include #pragma comment(lib,"WS2_32.lib") 用AfxSocket ...
- 进程间通信系列 之 socket套接字实例
进程间通信系列 之 概述与对比 http://blog.csdn.net/younger_china/article/details/15808685 进程间通信系列 之 共享内存及其实例 ...
- 【转】 VC中TCP实现 异步套接字编程的原理+代码
所谓的异步套接字编程就是 调用了 如下函数 WSAAsyncSelect 设置了 套接字的状态为异步,有关函数我会在下面详细介绍... 异步套接字解决了 套接字编程过程中的堵塞问题 .... ...
- DotNet:Socket Server 异步套接字服务端实现
异步服务器套接字示例 From https://msdn.microsoft.com/zh-cn/library/fx6588te(v=vs.110).aspx 下面的示例程序创建接收来自客户端的连接 ...
- java的套接字实现远程连接
package jnet;//客户端程序,使用套接字连接服务器import java.net.*;import java.io.*;import javax.swing.*; public class ...
- 异步套接字编程之select模型
█ 选择(select)模型是Winsock中最常见的 I/O模型.核心便是利用 select 函数,实现对 I/O的管理!利用 select 函数来判断某Socket上是否有数据可读,或者能否向 ...
- 异步套接字基础:select函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
参考:[原创]技术系列之 网络模型(三)多路复用模型 select函数 select函数: 系统提供select函数来实现多路复用输入/输出模型.原型: #include <sys/time.h ...
- Linux网络编程——原始套接字实例:MAC 头部报文分析
通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...
随机推荐
- java date类型和calendar类型区别
Date类 在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理.这里简单介绍一下Date ...
- day1之校花网小试牛刀
一 利用生成器来完成爬去校花网视频 import requests import re import os import hashlib import time DOWLOAD_PATH=r'D:\D ...
- 洛谷 P 1164 小A点菜
题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:“随便点”. 题目描述 不过uim由于买了一些辅(e ...
- 玩转css样式选择器----当父元素有多个子元素时选中最后一个
- WEB学习-HTML的基本语法特性
HTML对换行不敏感,对tab不敏感 HTML只在乎标签的嵌套结构,嵌套的关系.谁嵌套了谁,谁被谁嵌套了,和换行.tab无关. 换不换行.tab不tab,都不影响页面的结构. 所以: • <di ...
- kafka基础介绍
kafka基础介绍 一.kafka介绍 1.1主要功能 根据官网的介绍,kafka是一个分布式流媒体的平台,它主要有三大功能: 1.11:It lets you publish and subscri ...
- Java下接口interface前面要不要加I
说明:加I和不加I都可以,看需要,没有强制要求. 在Java中更多是提倡不加I的,可以看下JDK的源码,都是不加I的. 微软C#是规定要加I,这也是影响从而导致有这个话题的原因. Java中特定不直接 ...
- Nginx负载均衡配置实例(转)
1.轮询 轮询即Round Robin,根据Nginx配置文件中的顺序,依次把客户端的Web请求分发到不同的后端服务器.配置的例子如下: http{ upstream sampleapp { serv ...
- Redhat 5 无法安装elfutils-libelf-devel-0.137问题
http://whr25.blog.sohu.com/263584338.html 问题: RHEL5.5安装oracle11gR2的时候需要安装elfutils-libelf-devel-0.137 ...
- 实践与理解CMM体系
我的项目管理之路--5.实践与理解CMM体系 分类: 管理专辑(65) 过程改进(9) 软件工程(52) 版权声明:本文为博主原创文章,未经博主允许不得转载. 一个现代企业我们可以把它比作为自然界 ...