java中异步socket类的实现和源代码
java中异步socket类的实现和源代码
我们知道,java中socket类一般操作都是同步进行,常常在read的时候socket就会阻塞直到有数据可读或socket连接断开的时候才返回,虽然可以设置超时返回,但是这样比较低效,需要做一个循环来不停扫描数据是否可读。看来,在同一个线程中,要是想实现异步读写不太容易。
下面介绍的这个类实现了伪异步socket通讯。基本思想就是在现有socket类的基础上进行封装,当socket连接建立成功后,立即创建一个socket数据接收线程,专门负责阻塞式的socket读取(read),而当前线程负责数据的发送(send)。另外定义了一个接口,包括了socket的各种事件的回调。我们要实现这个接口,在接口实现类中创建异步socket对象,并且传递接口类到异步socket对象中,目的是有socket事件的时候回调我们的方法。
下面是接口:
SocketExHandler.java
package com.ly.net;
import java.net.*;
/**
* Title:
* Description:
* Copyright: Copyright (c) 2001
* Company: http://dozb.blogchina.com
* @author dozb
* @version 1.0
*/
/**
* 异步Socket Client Interface
* 使用方法:
* 1.定义类 MySocketClientEx 实现SocketExHandler接口,实现 OnReceive OnClose OnConnect 事件
* 2.在类中实现start方法 MySocketEx = new SocketEx(this,ip,port)
* 3.在类中实现stop方法 delete MySocketEx
* 4.当有数据到达时会触发OnReceive事件
* 5.当对方SOCKET关闭时会触发OnClose事件
* 6.当SOCKET建立时会触发OnConnect事件
*/
/**
* 异步Socket Server Interface
* 使用方法:
* 1.定义类 MySocketServerEx 实现SocketExHandler接口,实现 OnReceive OnListen OnClose OnAccept 事件
* 2.在类中实现start方法 MySocketEx = new ServerSocketEx(this,ip,port)
* 3.在类中实现stop方法 delete MySocketEx
* 4.当开始监听时会触发OnListen事件
* 5.当SOCKET关闭时会触发OnClose事件
* 6.当有客户端SOCKET要建立连接时会触发OnAccept事件
*/
public interface SocketExHandler
{
//当客户端sock数据到达时触发
public void OnReceive(Object socket,byte buf[],int nLen);
//当客户端sock连接建立成功时触发
public void OnConnect(Object socket);
//当服务端sock监听开始时触发
public void OnListen(Object socket);
//当服务端sock接受一个新的sock连接时触发
public void OnAccept(Object socket,SocketEx ClientSocket) ;
//当sock关闭时触发
public void OnClose(Object socket);
}
下面是异步客户端socket类:
SocketEx.java
package com.ly.net;
import java.io.*;
import java.net.*;
import java.util.*;
import com.ly.net.SocketExHandler;
/**
* Title:
* Description:
* Copyright: Copyright (c) 2001
* Company: http://dozb.blogchina.com
* @author dozb
* @version 1.0
*/
public class SocketEx implements Runnable
{
public static final boolean isdebug = true;//调试
/**
*构造函数.
*/
public SocketEx(SocketExHandler seh,Socket ClientSocket){this.seh = seh;thisSocket = ClientSocket; InitNotify();}
public SocketEx(SocketExHandler seh,String host,int port) throws IOException {this.seh = seh;thisSocket = new Socket(host,port);InitNotify();}
public SocketEx(SocketExHandler seh, InetAddress address, int port ) throws IOException {this.seh = seh;thisSocket = new Socket(address, port);InitNotify();}
public SocketEx(SocketExHandler seh, String host, int port, InetAddress localAddr, int localPort ) throws IOException {this.seh = seh;thisSocket = new Socket(host,port,localAddr,localPort );InitNotify();}
public SocketEx(SocketExHandler seh, InetAddress address, int port, InetAddress localAddr, int localPort ) throws IOException {this.seh = seh;thisSocket = new Socket(address, port, localAddr,localPort );InitNotify();}
/**
* 实现Socket的可见方法.
*/
public synchronized void close() throws IOException {IsRunning = false;thisSocket.close();}
public InetAddress getInetAddress() {return thisSocket.getInetAddress();}
public InputStream getInputStream() throws IOException{ return thisSocket.getInputStream(); }
public InetAddress getLocalAddress() { return thisSocket.getLocalAddress() ; }
public int getLocalPort() { return thisSocket.getLocalPort() ; }
public OutputStream getOutputStream() throws IOException{return thisSocket.getOutputStream(); }
public int getPort() { return thisSocket.getPort() ; }
public int getSoLinger() throws SocketException{ return thisSocket.getSoLinger(); }
public synchronized int getSoTimeout() throws SocketException { return thisSocket.getSoTimeout(); }
public boolean getTcpNoDelay() throws SocketException { return thisSocket.getTcpNoDelay(); }
public void setSoLinger( boolean on, int val ) throws SocketException { thisSocket.setSoLinger(on,val); }
public synchronized void setSoTimeout( int timeout ) throws SocketException {thisSocket.setSoTimeout( timeout ) ; }
public void setTcpNoDelay( boolean on ) throws SocketException {thisSocket.setTcpNoDelay(on); }
public String toString() { return thisSocket.toString() ; }
/**
* 获取Socket
*/
public Socket GetSocket(){return thisSocket;}
/**
* 初始化异步Socket
*/
private void ShowMsg(String Msg)
{
if(isdebug)
System.out.println(Msg);
}
private void InitNotify()
{
if(NotifyThread != null) return ;
try{
biStream = new BufferedInputStream(getInputStream());
thisSocket.setSoTimeout(0);
}catch(IOException e){
ShowMsg("InitNotify() IOException.");
}
IsRunning = true;
NotifyThread = new Thread(this,"SocketEx_NoitfyThread");
NotifyThread.setDaemon(true);
NotifyThread.start();
if(seh !=null)
seh.OnConnect(this);
}
/**
* 关闭Socket
*/
private void Close()
{
try{
close();
}catch(Exception eclose){
ShowMsg("Close() Exception.");
}
}
protected void finalize() throws Throwable
{
Close();
super.finalize();
}
/**
* Thread 运行
*/
public void run()
{
while(IsRunning){
try{
if(getInputStream().read(buf,0,1) <= 0)//试读一个字节
{
DoClose();
return ;
}
if(!DoReceive(getInputStream().available()))
return ;
}catch(Exception e){
ShowMsg("run() Exception.");
DoClose();
return ;
}
try{
Thread.sleep(0); //
}catch(InterruptedException e){
ShowMsg("run() InterruptedException.");
DoClose();
return ;
}
}
}
/**
* 当有数据到达时的回调方法.
*/
private boolean DoReceive(int nCanReadCount)
{
try{
int len = 0,nCurrReadCount=0,nStart=1;
do{
for(int i=nStart;i< BUFLEN;i++)
buf[i]=0;
if(nCanReadCount == 0)
{
if(seh !=null)
seh.OnReceive(this,buf,nStart);
return true;
}
if(nCanReadCount >(BUFLEN-2))
{
nCurrReadCount = BUFLEN-2;
}
else
{
nCurrReadCount = nCanReadCount;
}
len = biStream.read(buf,nStart,nCurrReadCount);
if(len == 0)
{
DoClose();
return false;
}
nCanReadCount -= len;
buf[len+nStart] = 0;
if(seh !=null)
seh.OnReceive(this,buf,len+nStart);
nStart = 0;
}while(nCanReadCount >0);
}catch(Exception excpt){
ShowMsg("DoReceive() Exception.");
DoClose();
return false;
}
return true;
}
/**
* 当Socket建立连接时的回调方法.
*/
private void DoConnect()
{
if(seh !=null)
seh.OnConnect(this);
}
/**
* 当Socket关闭时的回调方法.
*/
private void DoClose()
{
try{
if(IsRunning)
{
Close();
if(seh !=null)
seh.OnClose(this);
IsRunning = false;
}
}catch(Exception e){
ShowMsg("DoClose() Exception.");
}
}
/**
* 以下实现不要改动!!!!
*/
private Thread NotifyThread=null;
private boolean IsRunning = false;
private Socket thisSocket = null;
private static final int BUFLEN = 4097;
private byte buf[] = new byte[BUFLEN];
private BufferedInputStream biStream = null;
private SocketExHandler seh=null;
}
下面是异步socketserver类:
ServerSocketEx .java
package com.ly.net;
import java.io.*;
import java.net.*;
import java.util.*;
/**
* Title:
* Description:
* Copyright: Copyright (c) 2001
* Company: http://dozb.blogchina.com
* @author dozb
* @version 1.0
*/
public class ServerSocketEx extends ServerSocket implements Runnable
{
/**
* 以下实现不要改动!!!!
*/
public ServerSocketEx(SocketExHandler seh, int port ) throws IOException {super(port);this.seh = seh; Listen();}
public ServerSocketEx(SocketExHandler seh, int port, int backlog ) throws IOException {super(port,backlog);this.seh = seh; Listen();}
public ServerSocketEx(SocketExHandler seh, int port, int backlog, InetAddress bindAddr ) throws IOException {super(port,backlog, bindAddr);this.seh = seh;Listen();}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public static Vector GetClientPool(){return ClientPool;};
public static void CloseAllClients(){
for(int i=0;i< ClientPool.size();i++)
{
try{
SocketEx s=(SocketEx)ClientPool.elementAt(i);
if(s != null) s.close();
}catch(Exception e){}
}
ClientPool.removeAllElements();
}
public static void PutClient(SocketEx s){ClientPool.addElement(s);};
/**
* 关闭Socket
*/
public void Close()
{
IsRunning = false;
try{
close();
}catch(Exception eclose){
}
}
protected void finalize() throws Throwable
{
Close();
super.finalize();
}
/**
* Thread 运行
*/
public void run()
{
while(IsRunning){
acceptConnections();
}
DoClose();
}
// -------------------- Private methods
private void Listen() throws IOException
{
InitNotify();
if(seh !=null)
seh.OnListen(this);
}
/**
* 初始化异步Socket
*/
private void InitNotify()throws IOException
{
if(NotifyThread != null) return ;
try{
setSoTimeout(this.timeout);
} catch( IOException ex ) {
IsRunning=false;
throw ex;
}
IsRunning = true;
NotifyThread = new Thread(this,"ServerSocketEx_NoitfyThread");
NotifyThread.setDaemon(true);
NotifyThread.start();
}
/**
* 当Socket关闭时的回调方法.
*/
private void DoClose()
{
try{
if(seh !=null)
seh.OnClose(this);
//NotifyThread.stop();
}catch(Exception e){
}
}
private void processSocket(Socket s) throws IOException
{
SocketEx se = new SocketEx(seh,s);
PutClient(se);
if(seh !=null)
seh.OnAccept(this,se);
}
private void acceptConnections() {
try {
if(IsRunning == false)
return;
Socket socket = acceptSocket();
if(IsRunning != false && socket != null) {
processSocket(socket);
}
} catch(Throwable e) {
IsRunning = false;
}
}
private Socket acceptSocket() {
Socket accepted = null;
try {
if(IsRunning == true) {
accepted = accept();
if(IsRunning == false) {
if(null != accepted) {
accepted.close(); // rude, but unlikely!
accepted = null;
}
}
}
} catch(InterruptedIOException iioe) {
// normal part -- should happen regularly so
// that the endpoint can release if the server
// is shutdown.
// you know, i really wish that there was a
// way for the socket to timeout without
// tripping an exception. Exceptions are so
// 'spensive.
} catch (SocketException e) {
if (IsRunning != false) {
IsRunning = false;
}
} catch(Throwable e) {
IsRunning = false;
}
return accepted;
}
private static final int TIMEOUT = 5000;
private int timeout = TIMEOUT;
private Thread NotifyThread=null;
private boolean IsRunning=false;
private SocketExHandler seh=null;
private static Vector ClientPool=new Vector();
}
下面是几个工具类:
TimerClient.java
package com.ly.util;
/**
* TimerClient Interface
*
* @version 1.0, 8 October 1995
*
*/
public interface TimerClient
{
void timerEvent(int id);
}
TimerCtl.java
package com.ly.util;
import java.util.Vector;
import java.util.Enumeration;
//import com.borland.jb.util.Diagnostic;
/**
* Timer Component
*
* Note:
* - The successful operation of this timer requires clients to execute simple, short
* code snippets when called back by the engine. Otherwise the queue's delivery
* mechanism will be held up
*
* Further work:
* - When Thread.Interrupt is implemented we can switch from the busy wait model to
* the calculated wait model. Without the interrupt the thread waits for the
* calculated interval before waking up. This is a problem if another shorter
* request arrives. For now we'll assume the minimum resolution of the timer is
* 100ms.
*
* @version 1.0, 2 October 1995
*
*/
public class TimerCtl
{
static TimerTasks timerTasks;
public TimerCtl() {
}
/*
* Start a timer running
*/
public static void startTimer(TimerClient client, int eventId, long delay, boolean repeat) {
// create the timer if necessary
if (timerTasks == null) {
timerTasks = new TimerTasks();
timerTasks.start();
}
//Diagnostic.out.println("TIMER: startTimer"+eventId);
// add the new task to the queue
timerTasks.add(client, eventId, delay, repeat);
}
/*
* Stop a timer
*/
public static void stopTimer(TimerClient client, int eventId) {
//Diagnostic.out.println("TIMER: stopTimer"+eventId);
if(timerTasks != null)
timerTasks.end(client, eventId);
}
}
class TimerTasks extends Thread
{
Vector tasks = new Vector();
boolean suspended = false;
boolean sleeping = false;
/**
* Thread task runner
*/
public void run() {
// Loop forever
while (true) {
long sleepTime = 0;
// Ensure that the tasks class is protected
synchronized (tasks) {
//Diagnostic.out.println("TIMER: Tick");
// Scan the job list for any jobs which may fire.
// Mark one-shot jobs for deletion
// Calculate the maximum time we can sleep for
sleepTime = scan();
// Delete DeletePending jobs. DeletePending jobs result from one-shots which have
// been sent, and repeat jobs which have been cancelled. Jobs may have been
// cancelled during the Scan process.
purge();
}
// Suspend timer if necessary
if (tasks.size() == 0) {
//Diagnostic.out.println("TIMER: Suspend");
try {
synchronized(this) {
suspended = true;
wait();
}
}
catch (InterruptedException e) {
}
}
else {
//Diagnostic.out.println("TIMER: Suggested Sleeping for "+sleepTime);
if (sleepTime >= 0) {
try {
sleeping = true;
sleep(sleepTime);
sleeping = false;
}
catch (InterruptedException i) {
//Diagnostic.out.println("TIMER: Caught me napping");
}
}
}
}
}
/**
* Add a new task
*/
public void add(TimerClient client, int eventId, long delay, boolean repeat) {
TimerTask t = new TimerTask(client, eventId, delay, repeat);
synchronized (tasks) {
tasks.addElement((Object)t);
}
// Want instant response - wake the thread if it's napping
// unfortunately the interrupt() method is not working
// if (sleeping)
// interrupt();
if (suspended) {
synchronized(this) {
notify();
//Diagnostic.out.println("TIMER: Resume");
suspended = false;
}
}
}
/**
* Find the job and mark it for deletion
*/
public void end(TimerClient client, int eventId) {
synchronized (tasks) {
for (int i = 0; i < tasks.size(); i++) {
TimerTask t = (TimerTask)tasks.elementAt(i);
//if (!t.deletePending && t.client == client && t.eventId == eventId)
if (t.deletePending == false && t.client == client && t.eventId == eventId) {
// JPBS - if we don't reset 'repeat', deletePending will be set again
t.repeat = false;
t.deletePending = true;
break;
}
}
}
}
/**
* Clear out all the dead wood
*/
void purge() {
for (int i = 0; i < tasks.size(); i++) {
TimerTask t = (TimerTask)tasks.elementAt(i);
if (t.deletePending) {
//Diagnostic.out.println("TIMER: purged");
tasks.removeElementAt(i);
i--;
}
}
}
long scan() {
// The value added to the current time determines the MAX time until
// the next scan
// This is 100 now since thread.interrupt() is not implemented
long nextTime = System.currentTimeMillis() + 100;
for (int i = 0; i < tasks.size(); i++) {
TimerTask t = (TimerTask)tasks.elementAt(i);
// if not already deletePending, test (and possibly send the event)
// as a result, the job may be flagged for deletion.
// May also be a non-repeating job and so require self deletion
if (!t.deletePending)
t.test();
// if the task didn't get deleted - see what it contributes to the time
if (!t.deletePending)
nextTime = Math.min(nextTime, t.timeNext);
//Diagnostic.out.println("TIMER: Scanning "+t.eventId+" "+(t.deletePending == true ? "DEL" : ""));
}
return nextTime - System.currentTimeMillis();
}
}
class TimerTask
{
TimerClient client;
int eventId;
long timePrev;
long timeDelay;
long timeNext;
boolean repeat;
boolean deletePending;
public TimerTask(TimerClient client, int eventId, long timeDelay, boolean repeat) {
this.client = client;
this.eventId = eventId;
this.timeDelay = timeDelay;
this.repeat = repeat;
// schedule the next click - now + delay
timeNext = System.currentTimeMillis() + timeDelay;
deletePending = false;
//Diagnostic.out.println("TIMER: Adding New Task");
}
public void test() {
if (System.currentTimeMillis() >= timeNext) {
//Diagnostic.out.println("TIMER: fire");
// Fire the event
client.timerEvent(eventId);
// Update the next time
timeNext = System.currentTimeMillis() + timeDelay;
deletePending = !repeat;
}
}
}
下面是使用上面的异步socket类,做的demo开发
DemoAppSocketHandler.java
package com.ly.net;
import java.net.*;
import java.util.*;
/**
* Title:
* Description:
* Copyright: Copyright (c) 2001
* Company: http://dozb.blogchina.com
* @author dozb
* @version 1.0
*/
public interface DemoAppSocketHandler
{
//当客户端sock有数据到达时触发
public void OnProcessCmd(Object socket,String FromArea,String ToArea,String ChannNo,String MainFun,String SubFun,Vector ParamList);
//当客户端sock连接建立成功时触发
public void OnConnect(Object socket);
//当服务端sock监听开始时触发
public void OnListen(Object socket);
//当服务端sock接受一个新的sock连接时触发
public void OnAccept(Object socket,SocketEx ClientSocket) ;
//当sock关闭时触发
public void OnClose(Object socket);
}
DemoAppSocket.java
package com.ly.net;
import java.io.*;
import java.util.*;
import com.ly.util.*;
/**
* Title:
* Description:
* Copyright: Copyright (c) 2001
* Company: http://dozb.blogchina.com
* @author dozb
* @version 1.0
*/
//这个类是异步socket 客户端和服务端的使用演示
//对于客户端,实现了断开后自动连接
//这个类是SocketExHandler 和 TimerClient 接口的实现
public class DemoAppSocket implements SocketExHandler,TimerClient{
//Sock构造函数
public DemoAppSocket(DemoAppSocketHandler issh,boolean isServer,String ip,int port) {
this.issh = issh;
this.isServer = isServer;
this.ip = ip;
if(this.ip == null) this.ip = "";
this.port = port;
if(this.port <0) this.port = 0;
}
//调用完构造后调用这个函数创建sock对象
public void create()
{
if(!start())
TimerCtl.startTimer(this,eventId,30*1000,true);
}
//这个方法一般不需要直接调用
public boolean start()
{
if(this.isServer) return startServer(); else return startClient();
}
//停止socket
public void stop()
{
TimerCtl.stopTimer(this,eventId);
if(this.isServer) stopServer(); else stopClient();
}
//发送socket消息
public boolean SendCmd(Object socket,String strCmd)
{
SocketEx currSocketEx = (SocketEx)socket;
if(!isServer && currSocketEx==null) currSocketEx = socketEx;
if(currSocketEx == null) return false;
try{
PrintWriter Sender = new PrintWriter(currSocketEx.getOutputStream(),true);
Sender.print(strCmd);
Sender.flush();
return true;
}catch(Exception e)
{
return false;
}
}
//发送socket消息
public boolean SendCmd(Object socket,String FromArea,String ToArea,String ChannNo,String MainFun,String SubFun,String Param)
{
String strCmd = FromArea + ToArea + ChannNo + MainFun+SubFun+"&"+Param+"&";
return SendCmd(socket,strCmd);
}
//获得IP地址
public String getIp()
{
return ip;
}
//获得端口号
public int getPort()
{
return port;
}
protected boolean startClient()
{
if(socketEx != null) {
try{
socketEx.close();
}catch(IOException e){};
socketEx = null;
}
try{
socketEx = new SocketEx(this,ip,port);
TimerCtl.stopTimer(this,eventId);
return true;
}catch(IOException e)
{
socketEx = null;
}
return false;
}
protected boolean startServer()
{
if(serverSocketEx != null) {
try{
serverSocketEx.close();
}catch(IOException e){};
serverSocketEx = null;
}
try{
serverSocketEx = new ServerSocketEx(this,port);
TimerCtl.stopTimer(this,eventId);
return true;
}catch(IOException e)
{
serverSocketEx = null;
}
return false;
}
protected void stopServer()
{
if(serverSocketEx != null) {
try{
serverSocketEx.close();
}catch(IOException e){};
serverSocketEx = null;
}
}
protected void stopClient()
{
if(socketEx != null) {
try{
socketEx.close();
}catch(IOException e){};
socketEx = null;
}
}
public void timerEvent(int id)
{
start();
}
static public String[] DealStr(String strS)
{
int CMDHEAD_LEN = 22;
String[] ret = new String[2];//0留下的字符串1完整的CMD
ret[0]=strS;//
//假如只有一个&或没有&则不完整
int FirstPos=strS.indexOf("&");
if(FirstPos==-1)
return ret;
if(FirstPos != CMDHEAD_LEN-1)
{
strS = strS.substring(FirstPos+1);
return DealStr(strS);
}
int nSecondPos = strS.indexOf("&",FirstPos+1);
if(nSecondPos<0)
return ret;
//可能格式不正确了
if(strS.length()< CMDHEAD_LEN)
return ret;
ret[1] = strS.substring(0,nSecondPos+1);
ret[0]=strS.substring(nSecondPos+1);
return ret;
}
public void OnReceive(Object socket,byte buf[],int nLen){
String ReceiveBuff = sReceiveBuf + (new String(buf,0,nLen));
do//分解成单个的命令串
{
String strCmd[] = DealStr(ReceiveBuff);
ReceiveBuff = strCmd[0];
if(strCmd[1]==null || strCmd[1].equals("")) break;
System.out.println(strCmd[1]);
String FromArea=strCmd[1].substring(0,6);
String ToArea=strCmd[1].substring(6,12);
String ChannNo=strCmd[1].substring(12,15);
String MainFun=strCmd[1].substring(15,18);
String SubFun=strCmd[1].substring(18,21);
String Param =strCmd[1].substring(22,strCmd[1].length()-1);
Vector ParamList=new Vector();
int nLastPos=0;
while(true)
{
int nPos = Param.indexOf(",",nLastPos);
if(nPos <0)
{
ParamList.add(Param.substring(nLastPos));
// System.out.println(Param.substring(nLastPos));
break;
}
String sParam = Param.substring(nLastPos,nPos);
ParamList.add(sParam);
// System.out.println(sParam);
nLastPos = nPos+1;
}
DoProcessCmd(socket,FromArea,ToArea,ChannNo,MainFun,SubFun,ParamList);
}while(true);
sReceiveBuf = ReceiveBuff;
if(sReceiveBuf == null) sReceiveBuf=null;
}
protected void DoProcessCmd(Object socket,String FromArea,String ToArea,String ChannNo,String MainFun,String SubFun,Vector ParamList)
{
if(issh !=null)
issh.OnProcessCmd(socket,FromArea,ToArea,ChannNo,MainFun, SubFun, ParamList);
}
public void OnConnect(Object socket)
{
if(issh !=null) issh.OnConnect(socket);
}
public void OnListen(Object socket){
if(issh !=null) issh.OnListen(socket);
}
public void OnAccept(Object socket,SocketEx ClientSocket) {
if(issh !=null) issh.OnAccept(socket,ClientSocket);
}
public void OnClose(Object socket){
notifyAll();
TimerCtl.startTimer(this,eventId,30*1000,true);
if(issh !=null) issh.OnClose(socket);
}
//Socket
SocketEx socketEx = null;
ServerSocketEx serverSocketEx=null;
final int eventId = 1;
String sReceiveBuf="";
DemoAppSocketHandler issh=null;
boolean isServer=false;
String ip="127.0.0.1";
int port=20000;
}
通过这种方式,可以高效地使用socket通讯,在异步socket版本没有发布以前,不失是一种解决问题的方法。:)
相关文章:
java中异步socket类的实现和源代码
java中异步socket类的实现和源代码 我们知道,java中socket类一般操作都是同步进行,常常在read的时候socket就会阻塞直到有数据可读或socket连接断开的时候才返回,虽然可以设置超时返回,但是这样比较低效,需要做一个循环来不停扫描…...

ElasticSearch7.6入门学习笔记
在学习ElasticSearch之前,先简单了解一下Lucene: Doug Cutting开发 是apache软件基金会4 jakarta项目组的一个子项目 是一个开放源代码的全文检索引擎工具包不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的…...

《面试1v1》ElasticSearch架构设计
🍅 作者简介:王哥,CSDN2022博客总榜Top100🏆、博客专家💪 🍅 技术交流:定期更新Java硬核干货,不定期送书活动 🍅 王哥多年工作总结:Java学习路线总结…...
tomcat和nginx的日志记录请求时间
当系统卡顿时候,我们需要分析时间花费在哪个缓解。项目的后端接口可以记录一些时间,此外,在我们的tomcat容器和nginx网关上也可以记录一些有关请求用户,请求时间,响应时间的数据,可以提供更多的信息以便于排…...

数据结构——红黑树基础(博文笔记)
数据结构在查找这一章里介绍过这些数据结构:BST,AVL,RBT,B和B。 除去RBT,其他的数据结构之前的学过,都是在BST的基础上进行微小的限制。 1.比如AVL是要求任意节点的左右子树深度之差绝对值不大于1,由此引出…...
盘点帮助中心系统可以帮到我们什么呢?
在线帮助中心系统是一种强大的软件系统,可以让我们用来组织、管理、发布、更新和维护企业的宝贵知识库和用户文档。今天looklook就详细讲讲,除了大众所熟知的这些,帮助中心系统还有什么特别作用呢? 帮助中心系统的作用 1.快速自助…...

Web3 solidity编写交易所合约 编写ETH和自定义代币存入逻辑 并带着大家手动测试
上文 Web3 叙述交易所授权置换概念 编写transferFrom与approve函数我们写完一个简单授权交易所的逻辑 但是并没有测试 其实也不是我不想 主要是 交易所也没实例化 现在也测试不了 我们先运行 ganache 启动一个虚拟的区块链环境 先发布 在终端执行 truffle migrate如果你跟着我…...

概念解析 | 生成式与判别式模型在低级图像恢复与点云重建中的角力:一场较量与可能性探索
注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:生成式模型与判别式模型在低级图像恢复/点云重建任务中的优劣与特性。 生成式与判别式模型在低级图像恢复与点云重建中的角力:一场较量与可能性探索 1. 背景介绍 机器学习…...

【云原生】kubectl命令的详解
目录 一、陈述式资源管理方式1.1基本查看命令查看版本信息查看资源对象简写查看集群信息配置kubectl自动补全node节点查看日志 1.3基本信息查看查看 master 节点状态查看命名空间查看default命名空间的所有资源创建命名空间app删除命名空间app在命名空间kube-public 创建副本控…...

uniapp两个单页面之间进行传参
1.单页面传参:A --> B url: .....?code JSON.stringify(param), 2.单页面传参B–>Auni.$emit() uni.$on()...

uniapp运行项目到iOS基座
2022年9月,因收到苹果公司警告,目前开发者已无法在iOS真机设备使用未签名的标准基座,所以现在要运行到 IOS ,也需要进行签名。 Windows系统,HBuilderX 3.6.20以下版本,无法像MacOSX那样对标准基座进行签名…...

HTTP——九、基于HTTP的功能追加协议
HTTP 一、基于HTTP的协议二、消除HTTP瓶颈的SPDY1、HTTP的瓶颈Ajax 的解决方法Comet 的解决方法SPDY的目标 2、SPDY的设计与功能3、SPDY消除 Web 瓶颈了吗 三、使用浏览器进行全双工通信的WebSocket1、WebSocket 的设计与功能2、WebSocket协议 四、期盼已久的 HTTP/2.01、HTTP/…...
Redis 在电商秒杀场景中的应用
Redis 在电商秒杀场景中的应用 一、简介1.1 简介1.2 场景应用 二、Redis 优势与挑战2.1 优势2.2 秒杀场景的挑战 三、应用场景分析3.1 库存预热代码示例 3.2 分布式锁3.3 消息队列 四、系统设计方案4.1 架构设计4.2 技术选型4.3 数据结构设计 五、Redis 性能优化5.1 集群部署5.…...

大麦订单生成器 大麦一键生成订单
后台一键生成链接,独立后台管理 教程:修改数据库config/Conn.php 不会可以看源码里有教程 下载源码程序:https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3...

Java实现Google cloud storage 文件上传,Google oss
storage 控制台位置 创建一个bucket 点进bucket里面,权限配置里,公开访问,在互联网上公开,需要配置角色权限 新增一个访问权限 ,账号这里可以模糊搜索, 角色配置 给allUser配置俩角色就可以出现 在互联…...

适配器模式(AdapterPattern)
适配器模式 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。 优缺点 优点: 单一职责原则。你可以将接口或数据转换代码从程序主要业务逻辑中分…...

Apache Kafka Learning
目录 一、Kafka 1、Message Queue是什么? 2、Kafka 基础架构 3、Kafka安装 4、Offset自动控制 5、Acks & Retries 6、幂等性 7、事务控制 8、数据同步机制 9、Kafka-Eagle 二、Maven项目测试 1、Topic API 2、生产者&消费者 一、Kafka Kafka是…...

手把手教你用idea实现Java连接MySQL数据库
目录 1.下载MySQL 2.下载mysql 的jdbc驱动 3.将驱动jar包导入idea 4.通过Java测试数据库是否连接成功 1.下载MySQL 首先如果没有mysql的需要先下载MySQL,可以看这个教程 MYSQL安装手把手(亲测好用)_程序小象的博客-CSDN博客 2.下载mysql…...

Ubuntu 22.04安装和使用ROS1可行吗
可行。 测试结果 ROS1可以一直使用下去的,这一点不用担心。Ubuntu会一直维护的。 简要介绍 Debian发行版^_^ AI:在Ubuntu 22.04上安装ROS1是可行的,但需要注意ROS1对Ubuntu的支持只到20.04。因此,如果要在22.04上安装ROS1&am…...
83 | Python可视化篇 —— Bokeh数据可视化
Bokeh 是一种交互式数据可视化库,它可以在 Python 中使用。它的设计目标是提供一个简单、灵活和强大的方式来创建现代数据可视化,同时保持良好的性能。Bokeh 支持多种图表类型,包括线图、散点图、柱状图、饼图、区域图、热力图等。此外,它还支持将这些图表组合在一起以创建…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...