服务端

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异步套接字实例的更多相关文章

  1. 孙鑫MFC学习笔记16:异步套接字

    16 1.事件对象 2.CreateEvent创建事件对象 3.SetEvent设置事件对象为通知状态 4.ResetEvent设置事件对象为非通知状态 5.InitializeCriticalSec ...

  2. VC基于消息的异步套接字

    用WSAStartup,需要在StdAfx.h头文件中需要声明 #include    #pragma   comment(lib,"WS2_32.lib") 用AfxSocket ...

  3. 进程间通信系列 之 socket套接字实例

    进程间通信系列 之 概述与对比   http://blog.csdn.net/younger_china/article/details/15808685  进程间通信系列 之 共享内存及其实例   ...

  4. 【转】 VC中TCP实现 异步套接字编程的原理+代码

    所谓的异步套接字编程就是  调用了 如下函数   WSAAsyncSelect   设置了 套接字的状态为异步,有关函数我会在下面详细介绍... 异步套接字解决了 套接字编程过程中的堵塞问题 .... ...

  5. DotNet:Socket Server 异步套接字服务端实现

    异步服务器套接字示例 From https://msdn.microsoft.com/zh-cn/library/fx6588te(v=vs.110).aspx 下面的示例程序创建接收来自客户端的连接 ...

  6. java的套接字实现远程连接

    package jnet;//客户端程序,使用套接字连接服务器import java.net.*;import java.io.*;import javax.swing.*; public class ...

  7. 异步套接字编程之select模型

      █ 选择(select)模型是Winsock中最常见的 I/O模型.核心便是利用 select 函数,实现对 I/O的管理!利用 select 函数来判断某Socket上是否有数据可读,或者能否向 ...

  8. 异步套接字基础:select函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

    参考:[原创]技术系列之 网络模型(三)多路复用模型 select函数 select函数: 系统提供select函数来实现多路复用输入/输出模型.原型: #include <sys/time.h ...

  9. Linux网络编程——原始套接字实例:MAC 头部报文分析

    通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...

随机推荐

  1. 高通android7.0刷机工具使用介绍

    刷机工具安装 1. 安装QPST.WIN.2.7 Installer-00448.3 2. 安装python2.7,并配置其环境变量 刷机方法 1.将编译后的刷机文件拷贝到如下目录:SC20_CE_p ...

  2. R语言入门--画图(一)--需要注意的地方

    一.注意‘\t’是‘\t’     不是‘/t’  写'/t'就错了   就不是换行符了 二.程序报错先检查有没有这个包

  3. FastDFS上传/下载过程[转载-经典图列]

    FastDFS上传/下载过程: 首先客户端 client 发起对 FastDFS 的文件传输动作,是通过连接到某一台 Tracker Server 的指定端口来实现的,Tracker Server 根 ...

  4. 牛客练习赛1 矩阵 字符串二维hash+二分

    题目 https://ac.nowcoder.com/acm/contest/2?&headNav=www#question 解析 我们对矩阵进行二维hash,所以每个子矩阵都有一个额hash ...

  5. 浅谈云网融合与SD-WAN

    一.引言 近年来,SD-WAN作为一项新技术在行业应用领域里快速发展,企业对SD-WAN的接受度日渐提升,各厂商也纷纷提出解决方案.随着全球云计算领域的活跃创新和我国云计算发展进入应用普及阶段,越来越 ...

  6. delphi学习路线

     酷派(53376063) 11:04:19 1.语法基础PASCAL精要 先看个1-3遍,这是基础中的基础,只要没弄清楚看10遍都不多,当然最好结合着代码实例去看.(以后遇到哪儿不熟练继续反复看)2 ...

  7. websocket笔记

    本文为原创,转载请注明出处: cnzt       文章:cnzt-p http://www.cnblogs.com/zt-blog/p/6742746.html websocket -- 双向通信网 ...

  8. android开发教程之使用线程实现视图平滑滚动示例

    最近一直想做下拉刷新的效果,琢磨了好久,才走到通过onTouch方法把整个视图往下拉的步骤,接下来就是能拉下来,松开手要能滑回去啊.网上看了好久,没有找到详细的下拉刷新的例子,只有自己慢慢琢磨了.昨天 ...

  9. Liunx常用命令(备用)

    常用指令 ls        显示文件或目录 -l           列出文件详细信息l(list) -a          列出当前目录下所有文件及目录,包括隐藏的a(all) mkdir     ...

  10. Mac电脑解压文件unrar用密码问题解决

    下载了一个rar文件,有密码的,你懂的. 但是在mac上面,用unrar解压,只能解出空文件:用izip解压,直接停在那里不动. 只好上网搜索.找到了办法. 用brew 安装了命令行版本的 unrar ...