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 ...
随机推荐
- jenkins执行自动化用例(详细、有用、mark 优先级高高高)
http://blog.sina.com.cn/s/blog_68f262210102vx8o.html 第七章 测试用例接入jenkins自动运行 ------Web自动化测试之Webdriver+ ...
- polya burnside 专题
polya题目:uva 11077 Find the Permutationsuva 10294 Arif in DhakaLA 3641 Leonardo's Notebookuva 11077 F ...
- MySql将查询结果插入到另外一张表
今天遇到一个业务需求是这样的:对在职员工超过55岁提醒.我想的思路是查询员工表,然后将超过55岁的人的信息存到另一个表,并且以消息的形式给用户提示,用户处理掉之后此消息失效(在数据库做标记). 不管是 ...
- [OS X实用技巧]机器人应用:一键将图片转换为PNG/JPEG/TIFF
转自:http://www.maczhi.com/archives/2842.html 按教程老出错....试验了后使用: - 取得指定Finder对象,其它不变,但运行后不会出错. OS X实用技巧 ...
- Redis命令行之Set
一.Redis之Set简介 1. Set是String类型的无序集合(元素成员唯一). 2. Set是通过hash表实现的,添加.删除.查找的复杂度都是O(1). 3. 每个集合最大成员数为232-1 ...
- 测试开发系列之Python开发mock接口(三)
于进入主题了,前面的准备工作都已经做好了,下面就开始写逻辑的代码了,代码我已经写好了,每行都加了注释,不明白的可以留言. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 ...
- Spring的IoC容器-Spring BeanFactory容器
虽然这个方法已经在3.1之后已经弃用了,但是可以了解一下. 在Spring中,有大量对BeanFactory接口的实现.其中,最常被使用的是XmlBeanFactory类.这个容器从一个XML文件中读 ...
- php 处理大文件方法 SplFileObject
$csv_file = 'tmp.csv'; $start = isset($_GET['start']) ?intval($_GET['start']) : 1; // 从第几行开始读取 $num ...
- vueSSR渲染原理
优点:利于搜索引擎,解决白屏问题,因为正常情况下在index.html文件中只有一个简单的标签,没有内容,不利于爬虫搜索 场景:交互少,数据多,例如新闻,博客,论坛类等 原理:相当于服务端前面加了一层 ...
- PHP中文分词扩展 SCWS
1.scws简单介绍 SCWS 是 Simple Chinese Word Segmentation 的首字母缩写(即:简易中文分词系统). 这是一套基于词频词典的机械式中文分词引擎,它能将一整段的中 ...