JAVA自定义网络通信协议

 

       JAVA默认提供了对file,ftp,gopher,http,https,jar,mailto,netdoc协议的支持。当我们要利用这些协议来创建应用时,主要会涉及到如下几个类:

      1.java.net.URL:URL资源

      2.java.net.URLConnection:各种URL资源连接器

    例如,当我们利用HTTP协议获取Web资源时,通常的过程如下:

 

URL url = new URL("http://www.163.com");
URLConnection conneciotn = url.openConnection();

 

 

        URL和URLConnection是如何做到对协议支持的呢?在它们的内部,主要涉及到了如下几个类:

        1.URLStreamHandler:协议的流处理器,负责对特定URL协议的解析,并创建符合当前协议的URLConnection;

        2.URLStreamHandlerFactory:协议处理工厂,负责为特定协议找到正确的URLStreamHandler。

        当利用URL对象创建资源时,其构造函数在去掉协议字段后将其传给URLStreamHandlerFactory,由该工厂来接受协议,为该协议找到并创建适当的URLStreamHandler实现类,最后存储在URL对象的一个字段中(即URL类中transient修饰的URLStreamHandler成员属性)。
       URLStreamHandler和URLConnection总是成对出现的。因此,若要实现对新协议的支持时,需同时实现这两个抽象类,分别负责对协议的解析,以及与服务器的交互(数据转换等)。

      另外,JAVA是如何识别当前URL协议该由哪个URLStreamHandler和URLConnection来处理的呢?在创建URL对象时,其内部调用了一个getURLStreamHandler(String protocol)静态方法,它将根据协议的名称来找到对应的URLStreamHandler实现类,其查找规则如下:

     1)检测是否创建了URLStreamHandlerFactory对象:如果创建,则直接使用createURLStreamHandler(String protocol)方法创建的协议处理器,否则进入步骤2);

     2)在java.protocol.handler.pkgs系统属性指定的包中查找与协议同名的子包和名为Handler的类,即负责处理当前协议的URLStreamHandler实现类必须在的<包名>.<协议名定义的包>中,并且类名称必须为Handler。例如:com.company.net.protocol.rdp包中的Handler类将用于处理RDP协议。若仍未找到则进入步骤3);

    3)在JDK rt.jar中的sun.net.www.protocol.<name>包中查找Handler类。例如,若当前协议为ftp,则URL所使用协议处理器就应该为sun.net.www.protocol.ftp包中的Handler类。如下图:
         下面结合一个实例来说明如何开发一个新的网络协议。

          背景:senv(Server Environment Protocol)协议可让客户端连接远程服务器后发送出请求,请求的内容就是URL查询参数部分,该协议的默认端口为9527。例如:senv://192.168.1.101:9527?pro=os.name,java.version表示获取192.168.1.101这台主机的操作系统名和JRE的版本信息,如果没有查询参数,客户端将默认发送一个"?",表示获取所有的系统属性信息。

      
 1.Senv协议处理器

package com.daniele.appdemo.net.protocol.custom.senv;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;

/**
 * <p>
 * 		自定义的senv协议处理器。
 *      由于senv协议的格式符合标准的URL格式:
 *      	protocol://username@hostname:port/path/filename?query#fragment
 *      因此,这个实现类只需实现父类中的openConnection()方法即可。否则,需重写父类方法
 *      protected void parseURL(URL u, String spec, int start, int limit),
 *      来重新正确的设置URL的各个属性值,例如:host,port,query等。
 * </p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-5-8
 * @see     
 * @since   AppDemo1.0.0
 */
public class Handler extends URLStreamHandler {

	/**
	 * <p>当URL根据协议找到该处理器并调用openConnection()方法后,返回负责处理该协议连接的连接器</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @param u
	 * @return
	 * @throws IOException 
	 * @since AppDemo1.0.0
	 */
	@Override
	protected URLConnection openConnection(URL u) throws IOException {
		return new SenvURLConnection(u);
	}
	
}

 2.Senv协议连接器

package com.daniele.appdemo.net.protocol.custom.senv;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;

import com.daniele.appdemo.util.StringUtils;

/**
 * <p>自定义senv协议连接器</p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-5-8
 * @see     
 * @since   AppDemo1.0.0
 */
public class SenvURLConnection extends URLConnection {
	
	/** senv协议的默认端口号 */
	public static final int DEFAULT_PORT = 9527;
	
	private Socket connection = null;

	public SenvURLConnection(URL url) {
		super(url);
	}
	
	/**
	 * <p>由于父类URLConnection中的getInputStream()方法不提供输入流的获取实现逻辑,因此这里需要重写此方法</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @return
	 * @throws IOException 
	 * @since AppDemo1.0.0 
	 */
	@Override
	public synchronized InputStream getInputStream() throws IOException {
		if (!connected)
			this.connect();
		return connection.getInputStream();
	}
	
	/**
	 * <p>senv协议连接操作</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @throws IOException 
	 * @since AppDemo1.0.0 
	 */
	@Override
	public synchronized void connect() throws IOException {
		if (!connected) {
			int port = url.getPort();
			if (port < 1 || port > 65535)
				port = DEFAULT_PORT;
			this.connection = new Socket(url.getHost(), port);
			connected = true;
			// 连接后立即发送请求
			sendRequest(url);
		}
	}
	
	/**
	 * <p>发送senv协议请求</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @param u
	 * @throws IOException 
	 * @since AppDemo1.0.0
	 */
	protected void sendRequest(URL u) throws IOException {
		OutputStream outputStream = this.connection.getOutputStream();
		
		String queryString = u.getQuery();
		
		/*
		 *  将URL的查询参数部分发送给服务器,由服务器负责解析查询后返回结果。
		 *  当参数参数部分为空时,则发送一个"?",表示查询服务器系统环境的所有信息。
		 */
		outputStream.write(StringUtils.isNotNullOrBlank(queryString)? queryString.getBytes() : "?".getBytes());
		outputStream.flush();
	}

}

 

3.协议处理器工厂

package com.daniele.appdemo.net.protocol.factory;

import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;

/**
 * <p>
 *       自定义协议的处理器工厂,负责针对每种自定义的协议而返回它们各自对应的协议处理器
 *       如果要用上述的查找规则1来安装协议处理器时,则需要用到这个类
 *</p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-5-9
 * @see     
 * @since   AppDemo1.0.0
 */
public class CustomProtocolFactory implements URLStreamHandlerFactory {

	public URLStreamHandler createURLStreamHandler(String protocol) {
		if ("senv".equalsIgnoreCase(protocol))
			return new com.daniele.appdemo.net.protocol.custom.senv.Handler();
		return null;
	}

}

 

4.处理Senv协议的服务器

package com.daniele.appdemo.net.protocol.test;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
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.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;

import org.apache.log4j.Logger;

import com.daniele.appdemo.util.StringUtils;
import com.daniele.appdemo.util.SystemUtils;

/**
 * <p>处理Senv协议的服务器
 *    1.接收客户端请求
 *	  2.发送响应结果
 *  </p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-5-10
 * @see     
 * @since   AppDemo1.0.0
 */

public class SenvProtocolServer {
	
	private static final Logger logger = Logger.getLogger(SenvProtocolServer.class);
	
	/** Senv协议的请求参数标识 */
	public static final String REQUEST_PARAM_MARK = "pro=";
	
	/** Senv协议服务的默认端口号 */
	private static final int DEFAULT_PORT = 9527;

	/** 服务器的IP或主机名 */
	private String host;
	
	/** 绑定了Senv协议服务的端口号 */
	private int port = 9527;
	
	/** 当前就绪的服务端通道 */
	private ServerSocketChannel serverChannel;
	
	/** 当前就绪的客户端通道 */
	private SocketChannel clientChannel;
	
	/** 服务端的事件注册器 */
	private Selector selector;
	
	/**
	 * <p>启动Senv协议服务器</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @throws IOException 
	 * @since AppDemo1.0.0
	 */
	public void start() throws IOException {
		
		serverChannel = ServerSocketChannel.open();
		
		if (port < 1 || port > 65535)
			port = DEFAULT_PORT;
		
		if (StringUtils.isNotNullOrBlank(host)) {
			serverChannel.socket().bind(new InetSocketAddress(InetAddress.getByName(host), port));
			logger.info("Start server " + host + ":" + port);
		} else {
			serverChannel.socket().bind(new InetSocketAddress(port));
			logger.info("Start server on port " + port);
		}
		serverChannel.configureBlocking(false);
		selector = Selector.open();
        serverChannel.register(selector, SelectionKey.OP_ACCEPT); 
        handle();
	}
	
	/**
	 * <p>处理Senv协议请求</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @throws IOException 
	 * @since AppDemo1.0.0
	 */
	protected void handle() throws IOException {
		while (true) {
			selector.select();
			Iterator<SelectionKey> keySetIterator = selector.selectedKeys().iterator();
			SelectionKey cuurentKey = null;
			while (keySetIterator.hasNext()) {
				// 获取当前就绪通道的键对象
				cuurentKey = keySetIterator.next();
				// 避免同一个就绪通道被重复处理
				keySetIterator.remove();
				try {
					if (cuurentKey.isAcceptable()) {
						serverChannel = (ServerSocketChannel) cuurentKey.channel();
						clientChannel = serverChannel.accept();
						if (clientChannel != null) {
							logger.info("Receive request from " 
									+ clientChannel.socket().getInetAddress().getHostAddress() + ":"
									+ clientChannel.socket().getLocalPort());
							clientChannel.configureBlocking(false);
							clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
						} 
					} else {
						clientChannel = (SocketChannel) cuurentKey.channel();
						if (cuurentKey.isReadable()) 
							writeResponse();
					}
				} catch (IOException e) {
					if (clientChannel != null && clientChannel.isOpen())
						try {
							/*
							 *  为防止服务端在读写客户端信息时,客户端由于某种原因被意外关闭引起服务端也被强制关闭的情况发生。
							 *  需在catch块中也需要对客户端的通道做关闭处理, 从而防止服务端也被强制关闭的严重问题。
							 *  另外,对就绪通道的读写过程需单独的在一个try...catch块中。
							 */
							clientChannel.close();
						} catch (IOException ioe) {
							ioe.printStackTrace();
						}
				} 
			}
		}
	}
	
	/**
	 * <p>读取客户端请求</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @return 
	 * @throws IOException 
	 * @throws  
	 * @since AppDemo1.0.0
	 */
	protected String readRequest() throws IOException {
		StringBuffer request = new StringBuffer();
		CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		while (clientChannel.read(buffer) > 0) {
			buffer.flip();
			request.append(decoder.decode(buffer).toString());
			buffer.clear();
		}
		return request.toString();
	}
	
	/**
	 * <p>向客户端返回响应结果</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @throws IOException 
	 * @since AppDemo1.0.0
	 */
	protected void writeResponse() throws IOException {
		String request = readRequest();
		int start = -1;
		// 如果发送的请求为"?"或请求中无指定的参数时,则查询所有的系统环境属性
		if ("?".equals(request) || 
				(start = request.toLowerCase().indexOf(REQUEST_PARAM_MARK)) < 0) {
			clientChannel.write(ByteBuffer.wrap(SystemUtils.formatSystemProperties().getBytes()));
		} else {
			// 获取请求参数值
			String queryValueString = request.substring(start + REQUEST_PARAM_MARK.length());
			if (StringUtils.isNullOrBlank(queryValueString))
				clientChannel.write(ByteBuffer.wrap(SystemUtils.formatSystemProperties().getBytes()));
			else {
				int index = queryValueString.indexOf("&");
				if (index > -1)
					/*
					 *  如果请求参数值里出现了"&"字符,
					 *  则说明这个字符后面的内容则认为是其它一些请求参数的内容,
					 *  因此不对这部分内容作处理
					 */
					queryValueString = queryValueString.substring(0, index);
				clientChannel.write(ByteBuffer.wrap(SystemUtils.formatSystemProperties(queryValueString.split(",")).getBytes()));
			}
		}
		/*
		 *  响应内容被发送出去之后添加换行标识,
		 *  目的是让客户端的BufferedReader对象调用readLine()方法后能将当前行的内容读取出来
		 */
		clientChannel.write(ByteBuffer.wrap("\n".getBytes()));
		
		/*
		 *  发送完响应信息后马上关闭与客户端之间的通道。
		 *  目的在于让客户端读取完这些响应之后,就立即释放掉资源,从而让读操作不会一直处于阻塞状态
		 */
		clientChannel.close();
	}
	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public static void main(String[] args) {
		SenvProtocolServer server = new SenvProtocolServer();
		server.setHost("192.168.1.101");
		try {
			server.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

 

 4.Senv协议请求客户端

/**
 * <p>
 * 	  Senv协议请求的客户端,主要功能分为:
 *    1.在创建第一次创建URL对象之前,添加对自定义协议的支持
 *    2.发送请求
 *    3.展示响应数据
 * </p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-5-9
 * @see     
 * @since   AppDemo1.0.0
 */

public class SenvProtocolClient {
	
	public static void main(String[] args) {
		BufferedReader reader = null;
		try {
			// 配置协议处理器查找规则一
			if (StringUtils.isNullOrBlank(System.getProperty("java.protocol.handler.pkgs"))) {
				// 设置各个协议包所在的父包路径
				System.setProperty("java.protocol.handler.pkgs", "com.daniele.appdemo.net.protocol.custom");
			}
			/*
                         * 配置协议处理器查找规则二
                         * 这种方式在整个应用范围之内只能被执行一次。
                         * 如果多于一次则会出现"java.lang.Error: factory already defined"这样的错误。但不会受规则一的限制.
                         */ 
//			URL.setURLStreamHandlerFactory(new CustomProtocolFactory());
			
			URL url = new URL("senv://192.168.1.101:9527/");
			reader = new BufferedReader(new InputStreamReader(url.openConnection().getInputStream()));
			String result = "";
			while ((result = reader.readLine()) != null)
				System.out.println(result);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (reader != null)
					reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

 

package com.daniele.appdemo.util;

import java.util.Enumeration;
import java.util.Properties;

/**
 * <p>运行环境工具类</p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-5-9
 * @see     
 * @since   AppDemo1.0.0
 */

public class SystemUtils {
	
	private static Properties properties = null;
	
	static {
		properties = System.getProperties();
	}
	
	/**
	 * <p>返回格式化后的所有系统属性信息</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @return 
	 * @since AppDemo1.0.0
	 */
	@SuppressWarnings("unchecked")
	public static String formatSystemProperties() {
		StringBuffer formatResult = new StringBuffer();
		Enumeration<String> names = (Enumeration<String>) properties.propertyNames();
		while (names.hasMoreElements()) {
			String name = names.nextElement();
			formatResult.append(name).append("=")
				.append(properties.getProperty(name)).append("\n");
		}
		int length = 0;
		return (length = formatResult.length()) > 0 ? 
				formatResult.substring(0, length - 1) : "";
	}
	
	/**
	 * <p>返回格式化后的所有指定的系统属性信息</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @param propertyKeys
	 * @return 
	 * @since AppDemo1.0.0
	 */
	public static String formatSystemProperties(String[] propertyKeys) {
		StringBuffer formatResult = new StringBuffer();
		if (propertyKeys != null && propertyKeys.length > 0) {
			for (String key : propertyKeys) 
				formatResult.append(key).append("=")
					.append(properties.getProperty(key)).append("\n");
		}
		int length = 0;
		return (length = formatResult.length()) > 0 ? 
				formatResult.substring(0, length - 1) : "";
	}

}
package com.daniele.appdemo.util;

public class StringUtils {
	
	public static boolean isNullOrBlank(String str) {
		return str == null || str.length() == 0;
	}
	
	public static boolean isNotNullOrBlank(String str) {
		return !isNullOrBlank(str);
	}

}

运行时,依次启动SenvProtocolServer和SenvProtocolClient类即可。

 

客户端协议处理框架 java.net包下提供了一套客户端协议的处理框架,它是在传输层之上,提供了通过的应用层协议处理框架,比如基于这个框架可以实现处理HTTP协议客户端(ye'jiu'sh) 阅读详情

相关推荐

简易RPC框架实现——3、引入Netty实现网络通信

本章是在前面基于socket通信基础上的一种改进,引入了netty实现了客户端与服务端的网络通信,本章改动较大,对应的commit为cf7021b。 Netty是一个非阻塞I/O客户端-服务器框架,主要用于开发Java网络应用程序,如协议服务器和客户端。异步事件驱动的网络应用程序框架和工具用于简化网络编程,例如TCP和UDP套接字服务器。Netty包括了反应器编程模式的实现。(源自维基百科)。既然涉及到了网络编程,那么就离不开java中网络编程的王者——Netty。 Netty的使用方法本文不做过多赘述,如

fzzf__的博客 694

Java中如何注册协议

<br />      项目中需要在后台向第三方服务器发送Http请求,并且有一些特殊的要求。重写了HttpURLConnection的实现。但是怎么调用这个自定义的HttpURLConnection,而不是调用系统的sun.net.www.protocol.http.HttpURLConnection。<br />      通过查看java原代码(URL.openConnection)可以发现,不管哪种链接都是听过协议处理程序(handle)来取得的。而这个处理程序,是在新建URL对象时候,(听过get

Justin & Amber 的小屋 1089

Java网络通信系统开发全攻略:从Socket编程到毕业设计落地

网络通信是Java后端开发的核心能力,而Socket编程则是理解TCP/IP协议栈与应用层交互的基础。在多线程环境下,服务端如何高效管理连接、处理消息粘包与半包、维护用户在线状态,直接决定通信系统的可靠性与并发性能。本文从传输层协议选型、BIO与线程池模型、自定义协议设计等工程实践角度,系统梳理了Java网络通信系统的核心技术要点,并结合毕业设计场景,讲解了从开题报告、架构设计、源码实现到论文撰写与答辩的全流程方法。无论你是正在完成课程设计,还是希望夯实Java网络编程基础,都能从中获得一套可落地的思路与避

weixin_29597551的博客 233

深入理解Java类加载器(2):线程上下文类加载器

线程上下文类加载器 线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader()和 setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLo

Jack Zhou的专栏 4万+

深入探索前端调试神器vConsole

vConsole作为一款前端调试神器,为前端开发者提供了一个便捷的调试解决方案。通过本文的介绍和示例,相信你已经对vConsole有了更深入的了解。然而,vConsole的功能远不止于此,它还有许多高级用法和技巧等待你去发掘。讨论:你在前端开发中是如何使用vConsole的?你有没有发现vConsole的一些隐藏功能或技巧?欢迎在评论区分享你的经验和见解!💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!

一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身"农奴"把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟! 8522

利用mininet模拟SDN架构并进行DDoS攻击与防御模拟(Ryu+mininet+sflow+postman)

1、知识概述 (1)软件定义网络: (2)mininet: Mininet是一个强大的网络仿真平台,通过这个平台,我们可以很方便的模拟真实环境中的网络操作与架构。特别是SDN,在真实网络中进行相关的网络实验有一定难度,自然需要一个仿真平台可以学习这种新型的网络架构,而Mininet就应运而生,承担了这个光荣而艰巨的使命。Mininet自带交换机(switchs)、主机(hosts)、控制器(controllers),同时,在mininet上可以安装OpenvSwitch、多种控制器(NOX\POX

北风 1万+

SpringBoot项目导出可执行jar包,启动时报错:factory already defined

近期用springboot框架做了个小型项目,用来处理用户回复的消息相关。阿里云服务器上没有tomcat,所以打算将项目打包成jar运行。使用eclipse中的 项目右键 -> export -> 可执行jar,这种方式下的jar无法正常运行,报错如下: 严重: A child container failed during start java.util.concurrent.Ex...

chenhailonghp的博客 3394

汉字跨越三千年的生命力与数字时代适应性

文字作为文明载体,其演变规律始终遵循实用性与适应性的平衡。汉字作为现存最古老的文字系统,凭借形义结合的六书构造原理,实现了超方言的文化统一功能。在计算机处理方面,五笔输入法与Unicode支持证明了其技术兼容性,而视觉识别效率的先天优势使其在信息时代更具传播效力。从甲骨文识别AI到现代书法设计,汉字系统持续展现强大的文化承载力与技术适应性,这种活态传承为数字人文研究提供了独特样本。

weixin_29058331的博客 355

【Java】自定义协议

自定义协议是指针对特定需求或应用场景而设计的网络通信协议,它不同于常见的标准协议(如HTTP、FTP等),而是根据具体需要进行个性化开发。自定义协议可以满足一些特定的需求,例如提升通信效率、增强安全性、适配特殊硬件等。以下是设计自定义协议的一般步骤:确定需求和目标:明确自定义协议的目的、应用场景和要解决的问题。例如,如果希望在低带宽环境下传输大量数据,可以考虑设计一种高效的压缩算法。定义协议格式:确定自定义协议的数据格式,包括消息头、消息体以及可能的附加信息。这些格式应考虑到协议的可扩展性和兼容性。

m0_72670269的博客 1040

C#实战:通过ZPL指令与斑马打印机交互及状态监控全解析

本文全面解析了在C#中通过ZPL指令与斑马打印机进行交互及状态监控的实战方法。文章详细介绍了TCP/IP网络打印和Windows Raw打印两种核心连接方式,并深入讲解了ZPL指令的构建。重点阐述了通过SGD命令和斑马官方SDK实现实时打印状态监控的策略,为工业自动化场景下的可靠打印提供了完整解决方案。

weixin_29294395的博客 117

实测对比:DINOv2、CLIP、ResNet在图像相似度任务上谁更强?(含Python代码与避坑指南)

本文通过实测对比DINOv2、CLIP和ResNet在图像相似度任务中的表现,提供Python代码实现与避坑指南。实验结果显示,DINOv2在精度上表现最佳,CLIP在多模态场景中优势明显,而ResNet则在计算效率上更优。文章还针对不同业务场景给出了具体选型建议,帮助开发者在图像搜索和版权检测等项目中做出更明智的技术决策。

weixin_30588381的博客 286

Java网络通信进阶:彻底解决TCP粘包拆包问题,手写自定义通信协议+消息解码器

消息头+长度域(行业最优) 消息头部固定4字节存储消息体长度,先读长度,再读对应字节消息体 无内容限制、无带宽浪费、适配所有消息格式 编码解码逻辑稍复杂 RPC、IM、网关、绝大多数互联网网络服务。消息头+消息体+校验位 在长度域基础上增加消息类型、序列号、校验码 支持消息重试、异常校验、消息分类 协议最复杂,开发成本最高 金融、支付、工业级高可靠网络通信。固定消息长度 每条消息统一固定字节长度,不足补空字符 实现最简单,逻辑直观 浪费网络带宽,长消息不够用,短消息冗余 短消息、格式固定的内网通信。

SummerJokes的博客 209

【K8S系列】Kubernetes 中 Service 的流量不均匀问题【已解决】

在 Kubernetes 中,Service 是一种抽象,用于定义一组 Pod 的访问策略。当某些 Pod 接收的流量过多,而其他 Pod 的流量较少时,可能会导致负载不均衡。这种情况不仅影响性能,还可能导致某些 Pod 过载,影响应用的可用性。本文将详细分析此问题的原因及其解决方案。

颜淡慕潇 8739

android自定义url协议,Android使用自定义TCP协议访问网络(以二进制流的方式)

由于服务器是自己搭建,直接使用TCP的Socket进行访问,并且传输的是自定义格式数据帧,只提供主机地址和端口号,并没有请求的url,所以请求服务器不能使用现在的OKHttp等访问网络的框架。协议规范协议头+协议内容协议头MAGIC+LENGHTMAGIC:魔数, 固定为”0x8EEEEEEE”(自定义的十六进制), unsigned int型, 4个字节LENGTH:协议内容的长度, unsig...

weixin_29081703的博客 487

【CloudCompare教程】017:点云快速全局配准

点云数据的配准分为基于特征(特征点、特征线)的拼接和无特征拼接。特征点匹配的方法和全局ICP的方法。特征点的方法通过全局特征匹配达到全局配准,全局ICP的方法通过对变量空间进行搜索的方法达到全局最优解。

智慧空间实验室 3929

PreScan快速入门到精通第二十一讲驾驶员模型之驾驶员在环

请注意,操纵杆的输出角度是以度为单位的,而方向盘执行器希望其输入是以弧度为单位的。当选择一个支持的方向盘时,PreScan会自动将按钮映射到正确的功能上(如换挡),并设置轴的正确范围(如转向角度)。该系统中的所有其他组件都是为了提供正确的按钮映射,并为所选的方向盘设置正确的范围。对于每一个额外连接的控制器,它们的ID会增加一个,例如第二个控制器的设备ID为1,第三个控制器的设备ID为2,等等。由于所有的方向盘最初放在编译表上的设备ID都是0,所以用户应该先进行正确的调整,将每个控制器设置为正确的设备ID。.

小明师兄的博客 1423

Java网络通信实战:私聊功能从协议设计到消息路由的完整实现

Java网络通信是构建即时通讯系统的技术基石,其中Socket编程与多线程并发机制是开发者必须掌握的核心技能。在群聊转向私聊的过程中,开发者需要面对身份标识、在线状态管理和精准消息路由等更复杂的挑战,而不仅仅是简单的广播逻辑过滤。本文基于一个可运行的私聊项目,深入剖析服务端在线用户管理(ConcurrentHashMap的应用与踢线策略)、自定义JSON消息协议设计、以及客户端接收线程与界面刷新的协作方式。同时,结合高频踩坑案例,如连接假死、中文乱码、死连接路由等问题,给出清晰的排查链路与解决思路。无论您是

weixin_30074763的博客 222

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Netty4.0学习笔记系列之五:自定义通讯协议

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34148340的博客 79

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

基于Java Socket的自定义协议,实现Android与服务器的长连接(一)

一、基础知识准备 在正式给大家介绍自定义协议之前,我们先对网络传输和协议解析的相关知识点做一个基本的介绍,尽管这些知识点我们在学校里学过,但难免会有所遗忘,这里先做一个简单的介绍,以便对后文的内容理解更加顺畅。 1. 网络七层协议 OSI的7层从上到下分别是:7 应用层、 6 表示层、 5 会话层、 4 传输层、 3 网络层、 2 数据链路层、 1 物理层;其中高层(即7、6、5、4层)定义

枚杉的专栏 9840

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

AsyncHttpClient自定义协议开发终极指南:从零构建高性能通信框架

AsyncHttpClient是一个功能强大的**异步HTTP客户端库**,专为Java应用程序设计,提供高效的HTTP请求执行和异步响应处理能力。这个库不仅支持标准的HTTP协议,还提供了灵活的自定义协议开发框架,让开发者能够构建高性能的通信解决方案。🚀 ## 什么是AsyncHttpClient自定义协议? AsyncHttpClient的自定义协议功能允许开发者扩展和定制通信协议,满足

gitblog_00172的博客 775

C#、Unity网络通信中基于字节码的自定义协议解码,C#版ByteBuffer

C#、Unity网络通信中基于字节码的自定义协议解码,C#版ByteBuffer http://www.oschina.net/code/snippet_42170_37516 C#、Unity基于字节的网络通信中字节码解析类,类似java中的ByteBuffer,不过这个实现是参考的netty4中的ByteBu...

N的专栏 232

Java项目--仿RabbitMQ的消息队列--网络通信协议设计

本篇文章就介绍一下本次项目的最后一个大的部分,网络通信协议的设计。

m0_74815183的博客 1090

async-http-client自定义协议集成:终极步骤指南

在现代Java应用程序开发中,异步HTTP客户端已成为处理高并发网络请求的关键工具。**async-http-client**作为一款强大的异步HTTP和WebSocket客户端库,提供了灵活的配置选项,特别是支持自定义协议集成,让开发者能够根据特定需求优化网络通信性能。😊 ## 为什么需要自定义协议集成? 在复杂的网络环境中,标准的HTTP协议可能无法满足所有业务需求。通过自定义协议集成,

gitblog_00823的博客 1101

DICOM:DICOM3.0网络通信协议之“开源库实现剖析”

背景:日前,通过对比fo-dicom与dcm4che两种开源库(也是C#与Java两大语言体系)的不同实现来实战学习了DICOM的网络传输,博文中列举了两大开源库各自的实现特点,以及使用的语言特性。本篇继续对比两大开源库,从宏观整体来分析各自DICOM Protocol的实现,聚焦各自使用的线程池,以及管理方式……

只要踏出一步,路就在前方——zssure 1万+

java ServerSocket 直接写 是否还有价值

太有价值了!

lydstory123的专栏 263

Java网络通信消息协议设计:从粘包半包到Netty编解码实践

在Java网络编程中,TCP本质上是字节流而非消息流,这导致开发者经常面临粘包与半包问题。理解消息协议设计是解决这一问题的核心,它通过定义帧边界、字段规划和校验机制,让通信双方拥有明确的契约。从底层原理看,自定义私有协议通常采用长度前缀方式,接收方先解析消息头中的长度字段,再精确读取消息体,从而避免数据错位。技术价值体现在提升系统稳定性与可扩展性,无论是IoT设备接入、即时通讯还是RPC框架,都依赖可靠的编解码设计。在实际工程中,Netty提供的LengthFieldBasedFrameDecoder能高效

weixin_32325225的博客 240
上一篇: 64位系统上使用PLSQL Developer的解决方案
下一篇: JAVA RMI分布式原理和应用
心如止水dy
博客等级 码龄19年 5粉丝 16原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值