69 changed files with 504 additions and 622 deletions
@ -1,153 +0,0 @@ |
|||||
package com.xr.device_car.config.utils; |
|
||||
|
|
||||
|
|
||||
import com.xr.device_car.modules.analysis.entity.BallheadPT; |
|
||||
import org.apache.commons.lang.StringEscapeUtils; |
|
||||
import org.dom4j.Document; |
|
||||
import org.dom4j.Element; |
|
||||
import org.dom4j.io.SAXReader; |
|
||||
|
|
||||
import java.io.ByteArrayInputStream; |
|
||||
import java.nio.charset.StandardCharsets; |
|
||||
import java.util.ArrayList; |
|
||||
import java.util.List; |
|
||||
import java.util.stream.Collectors; |
|
||||
|
|
||||
public class AnalysisXml { |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 解析xml[Profiles] 获取 token |
|
||||
* @param resultStr |
|
||||
* @return |
|
||||
*/ |
|
||||
public static List<String> analysisTokens(String resultStr){ |
|
||||
// 解析body
|
|
||||
// 转换返回结果中的特殊字符,返回的结果中会将xml转义,此处需要反转移
|
|
||||
String xmlStr = StringEscapeUtils.unescapeXml(resultStr); |
|
||||
SAXReader reader = new SAXReader(); |
|
||||
try { |
|
||||
Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8))); |
|
||||
Element root = document.getRootElement(); |
|
||||
List<Element> elements = root.element("Body").element("GetProfilesResponse").elements("Profiles"); |
|
||||
return elements.stream().map(element -> element.attribute("token").getText()).collect(Collectors.toList()); |
|
||||
} catch (Exception e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
/** |
|
||||
* 解析xml[ProfilesName] 获取 token |
|
||||
* @param resultStr |
|
||||
* @return |
|
||||
*/ |
|
||||
public static List<String> analysisProfiles(String resultStr){ |
|
||||
// 解析body
|
|
||||
// 转换返回结果中的特殊字符,返回的结果中会将xml转义,此处需要反转移
|
|
||||
String xmlStr = StringEscapeUtils.unescapeXml(resultStr); |
|
||||
SAXReader reader = new SAXReader(); |
|
||||
try { |
|
||||
Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8))); |
|
||||
Element root = document.getRootElement(); |
|
||||
List<Element> elements = root.element("Body").element("GetProfilesResponse").elements("Preset"); |
|
||||
return elements.stream().map(element -> element.element("Name").getText() |
|
||||
).collect(Collectors.toList()); |
|
||||
} catch (Exception e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
/** |
|
||||
* 解析xml[MediaUri] 获取 token |
|
||||
* @param resultStr |
|
||||
* @return |
|
||||
*/ |
|
||||
public static String analysisSnapshotUrl(String resultStr){ |
|
||||
// 解析body
|
|
||||
// 转换返回结果中的特殊字符,返回的结果中会将xml转义,此处需要反转移
|
|
||||
String xmlStr = StringEscapeUtils.unescapeXml(resultStr).replace("&", "&"); |
|
||||
SAXReader reader = new SAXReader(); |
|
||||
try { |
|
||||
Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8))); |
|
||||
Element rootElement = document.getRootElement(); |
|
||||
Element element = rootElement.element("Body").element("GetSnapshotUriResponse").element("MediaUri"); |
|
||||
List<Element> elements=element.elements("Uri"); |
|
||||
return String.valueOf(elements.get(0).getData()); |
|
||||
} catch (Exception e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 解析xml[MediaUri] 获取 streamUrl |
|
||||
* @param resultStr |
|
||||
* @return |
|
||||
*/ |
|
||||
public static String analysisStreamUrl(String resultStr){ |
|
||||
// 解析body
|
|
||||
// 转换返回结果中的特殊字符,返回的结果中会将xml转义,此处需要反转移
|
|
||||
String xmlStr = StringEscapeUtils.unescapeXml(resultStr).replace("&", "&"); |
|
||||
SAXReader reader = new SAXReader(); |
|
||||
try { |
|
||||
Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8))); |
|
||||
Element rootElement = document.getRootElement(); |
|
||||
Element element = rootElement.element("Body").element("GetStreamUriResponse").element("MediaUri"); |
|
||||
List<Element> elements=element.elements("Uri"); |
|
||||
return String.valueOf(elements.get(0).getData()); |
|
||||
} catch (Exception e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
public static List<BallheadPT> getBallheadPTs(String resultStr){ |
|
||||
List<BallheadPT> ballheadPTS=new ArrayList<>(); |
|
||||
String xmlStr = StringEscapeUtils.unescapeXml(resultStr).replace("&", "&"); |
|
||||
SAXReader reader = new SAXReader(); |
|
||||
try { |
|
||||
Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8))); |
|
||||
Element root = document.getRootElement(); |
|
||||
List<Element> elements = root.element("Body").element("GetPresetsResponse").elements("Preset"); |
|
||||
for(Element element:elements){ |
|
||||
BallheadPT pt=new BallheadPT(); |
|
||||
String id = element.attribute(0).getValue(); |
|
||||
pt.setId(id); |
|
||||
String name = String.valueOf(element.element("Name").getText()); |
|
||||
pt.setName(name); |
|
||||
List<Element> ele=element.elements("PTZPosition"); |
|
||||
pt.setX(String.valueOf(ele.get(0).element("PanTilt").attribute(0).getValue())); |
|
||||
pt.setY(String.valueOf(ele.get(0).element("PanTilt").attribute(1).getValue())); |
|
||||
pt.setZ(String.valueOf(ele.get(0).element("Zoom").attribute(0).getValue())); |
|
||||
ballheadPTS.add(pt); |
|
||||
} |
|
||||
} catch (Exception e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return ballheadPTS; |
|
||||
} |
|
||||
|
|
||||
public static BallheadPT getStatus(String resultStr){ |
|
||||
String xmlStr = StringEscapeUtils.unescapeXml(resultStr).replace("&", "&"); |
|
||||
SAXReader reader = new SAXReader(); |
|
||||
try { |
|
||||
Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8))); |
|
||||
Element root = document.getRootElement(); |
|
||||
Element element = root.element("Body").element("GetStatusResponse").element("PTZStatus").element("Position"); |
|
||||
String x=String.valueOf(element.element("PanTilt").attribute(0).getValue()); |
|
||||
String y=String.valueOf(element.element("PanTilt").attribute(1).getValue()); |
|
||||
String z=String.valueOf(element.element("Zoom").attribute(0).getValue()); |
|
||||
BallheadPT pt=new BallheadPT(); |
|
||||
pt.setX(x); |
|
||||
pt.setY(y); |
|
||||
pt.setZ(z); |
|
||||
return pt; |
|
||||
} catch (Exception e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
} |
|
||||
@ -1,52 +0,0 @@ |
|||||
package com.xr.device_car.config.utils; |
|
||||
|
|
||||
import com.xr.device_car.modules.analysis.entity.BallheadPT; |
|
||||
import com.xr.device_car.modules.analysis.entity.DeviceCamera; |
|
||||
import com.xr.device_car.modules.analysis.entity.OnvifAuthBean; |
|
||||
import com.xr.device_car.modules.analysis.entity.OnvifBean; |
|
||||
import org.springframework.util.CollectionUtils; |
|
||||
|
|
||||
import java.awt.image.BufferedImage; |
|
||||
import java.util.List; |
|
||||
|
|
||||
public class HkComUtil { |
|
||||
|
|
||||
public static BufferedImage getBole(DeviceCamera device) throws Exception{ //拉取枪机图片
|
|
||||
OnvifAuthBean onvifBean= new OnvifAuthBean(device.getDeviceIp(),80,device.getAccount(),device.getPassword()); |
|
||||
String url= OnvifBean.getRequestUrl(onvifBean); |
|
||||
String auth = OnvifUtils.getAuthorization("digest",onvifBean,"digest/GetProfiles.wsdl", url); |
|
||||
System.out.println("鉴权:"+auth); |
|
||||
//获取Token
|
|
||||
List<String> profileTokens = OnvifUtils.getProfileTokens(onvifBean,auth); |
|
||||
System.out.println("Token:"+profileTokens); |
|
||||
onvifBean.setAuth(auth); |
|
||||
if(!CollectionUtils.isEmpty(profileTokens)){ |
|
||||
String snapshotUrl=null; |
|
||||
String token = profileTokens.get(0); |
|
||||
BallheadPT ballheadPT=OnvifUtils.getPtzStatus(token,onvifBean); |
|
||||
//如果类型是球机转换指定点位
|
|
||||
if(device.getDeviceType().equals("3") && OnvifUtils.ptzCamera(token,onvifBean,device.getX(),device.getY(),device.getZ())){ |
|
||||
Thread.sleep(1000); |
|
||||
//拉取图片
|
|
||||
snapshotUrl = OnvifUtils.getSnapshotUrl(token,onvifBean); |
|
||||
if(snapshotUrl!=null){ |
|
||||
//转回原来位置
|
|
||||
OnvifUtils.ptzCamera(token,onvifBean,ballheadPT.getX(),ballheadPT.getY(),ballheadPT.getZ()); |
|
||||
} |
|
||||
//如果类型是固定枪机,直接获取图片
|
|
||||
}else{ |
|
||||
snapshotUrl = OnvifUtils.getSnapshotUrl(token,onvifBean); |
|
||||
} |
|
||||
//返回图片地址
|
|
||||
return Files.urlByImages(snapshotUrl,device.getAccount(),device.getPassword()); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
@ -1,141 +0,0 @@ |
|||||
package com.xr.device_car.config.utils; |
|
||||
|
|
||||
import com.xr.device_car.config.common.RESTClient; |
|
||||
import com.xr.device_car.modules.analysis.entity.BallheadPT; |
|
||||
import com.xr.device_car.modules.analysis.entity.DigestBean; |
|
||||
import com.xr.device_car.modules.analysis.entity.OnvifAuthBean; |
|
||||
import com.xr.device_car.modules.analysis.entity.OnvifBean; |
|
||||
import org.springframework.core.io.ClassPathResource; |
|
||||
import org.springframework.util.StringUtils; |
|
||||
|
|
||||
import java.util.List; |
|
||||
|
|
||||
import static com.xr.device_car.config.common.Const.HEADERS_ONVIF_WWW_AUTHENTICATE; |
|
||||
|
|
||||
|
|
||||
public class OnvifUtils { |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 获取鉴权 |
|
||||
* @param authType |
|
||||
* @param requestOnvifBean |
|
||||
* @param wsdl |
|
||||
* @param requestUrl |
|
||||
* @return |
|
||||
*/ |
|
||||
public static String getAuthorization(String authType, OnvifBean requestOnvifBean, String wsdl, String requestUrl) { |
|
||||
//参数
|
|
||||
// 读取GetProfiles.wsdl
|
|
||||
String getProfiles = FileUtil.fileReader(new ClassPathResource(wsdl)); |
|
||||
HttpResponseBean httpResponseBean = RESTClient.getClientConnectionPool() |
|
||||
.postXML(requestUrl, getProfiles); |
|
||||
//如果是401的话 获取WWW-Authenticate 重新请求
|
|
||||
if (HttpResponseBean.isUnAuthorzied(httpResponseBean)) { |
|
||||
DigestBean digestBean = new DigestBean().getDigestBean(authType,requestOnvifBean, httpResponseBean.getFirstHeader(HEADERS_ONVIF_WWW_AUTHENTICATE).getValue()); |
|
||||
return digestBean.getToken(); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 获取Token |
|
||||
* @param requestOnvifBean |
|
||||
* @param auth |
|
||||
* @return |
|
||||
*/ |
|
||||
public static List<String> getProfileTokens(OnvifBean requestOnvifBean, String auth) { |
|
||||
//请求url
|
|
||||
String requestUrl = OnvifBean.getRequestUrl(requestOnvifBean); |
|
||||
//参数
|
|
||||
// 读取GetProfiles.wsdl
|
|
||||
String getProfiles = FileUtil.fileReader(new ClassPathResource("digest/GetProfiles.wsdl")); |
|
||||
HttpResponseBean httpResponseBean = RESTClient.getClientConnectionPool() |
|
||||
.postXML(requestUrl, getProfiles,auth); |
|
||||
if(httpResponseBean != null) { |
|
||||
String resultStr = httpResponseBean.getBody(); |
|
||||
if (HttpResponseBean.isSuccess(httpResponseBean) && StringUtils.hasLength(resultStr)) { |
|
||||
return AnalysisXml.analysisTokens(resultStr); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 获取截图地址 |
|
||||
* @param profileToken token |
|
||||
* @param requestOnvifBean |
|
||||
* @return |
|
||||
*/ |
|
||||
public static String getSnapshotUrl(String profileToken, OnvifAuthBean requestOnvifBean) { |
|
||||
String requestUrl = OnvifBean.getRequestUrl(requestOnvifBean); |
|
||||
//参数
|
|
||||
// 读取GetProfiles.wsdl
|
|
||||
String snapshotUrlWsdl = FileUtil.fileReader(new ClassPathResource("digest/GetSnapshotUrl.wsdl")); |
|
||||
HttpResponseBean httpResponseBean = RESTClient.getClientConnectionPool() |
|
||||
.postXML(requestUrl, String.format(snapshotUrlWsdl,profileToken),requestOnvifBean.getAuth()); |
|
||||
String resultStr = httpResponseBean.getBody(); |
|
||||
if(StringUtils.hasLength(resultStr) && HttpResponseBean.isSuccess(httpResponseBean)) { |
|
||||
return AnalysisXml.analysisSnapshotUrl(resultStr); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
//绝对位置转动球机
|
|
||||
public static boolean ptzCamera(String profileToken,OnvifAuthBean requestOnvifBean,String x,String y,String z){ |
|
||||
String requestUrl = OnvifBean.getRequestUrl(requestOnvifBean); |
|
||||
String snapshotUrlWsdl = FileUtil.fileReader(new ClassPathResource("digest/AbsoluteMove.wsdl")); |
|
||||
String wsdl = String.format(snapshotUrlWsdl,profileToken,x,y,z); |
|
||||
HttpResponseBean httpResponseBean = RESTClient.getClientConnectionPool() |
|
||||
.postXML(requestUrl, wsdl,requestOnvifBean.getAuth()); |
|
||||
String resultStr = httpResponseBean.getBody(); |
|
||||
if(StringUtils.hasLength(resultStr) && HttpResponseBean.isSuccess(httpResponseBean)) { |
|
||||
return true; |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
//获取球机当前位置
|
|
||||
public static BallheadPT getPtzStatus(String token,OnvifAuthBean requestOnvifBean){ |
|
||||
String requestUrl = OnvifBean.getRequestUrl(requestOnvifBean); |
|
||||
String snap = FileUtil.fileReader(new ClassPathResource("digest/GetStatus.wsdl")); |
|
||||
String wsdl = String.format(snap,token); |
|
||||
HttpResponseBean httpResponseBean = RESTClient.getClientConnectionPool() |
|
||||
.postXML(requestUrl, wsdl,requestOnvifBean.getAuth()); |
|
||||
String resultStr = httpResponseBean.getBody(); |
|
||||
if(StringUtils.hasLength(resultStr) && HttpResponseBean.isSuccess(httpResponseBean)) { |
|
||||
return AnalysisXml.getStatus(resultStr); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
//获取所有预置点
|
|
||||
public static List<BallheadPT> getBallHeadPts(String profileToken,OnvifAuthBean requestOnvifBean){ |
|
||||
String requestUrl = OnvifBean.getRequestUrl(requestOnvifBean); |
|
||||
String snapshotUrlWsdl = FileUtil.fileReader(new ClassPathResource("digest/GetPresets.wsdl")); |
|
||||
String wsdl = String.format(snapshotUrlWsdl,profileToken); |
|
||||
HttpResponseBean httpResponseBean = RESTClient.getClientConnectionPool() |
|
||||
.postXML(requestUrl, wsdl,requestOnvifBean.getAuth()); |
|
||||
String resultStr = httpResponseBean.getBody(); |
|
||||
if(StringUtils.hasLength(resultStr) && HttpResponseBean.isSuccess(httpResponseBean)) { |
|
||||
return AnalysisXml.getBallheadPTs(resultStr); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
//前往指定预置点
|
|
||||
public static boolean gotoBallHeadPts(String profileToken, OnvifAuthBean requestOnvifBean, BallheadPT ballheadPT){ |
|
||||
String requestUrl = OnvifBean.getRequestUrl(requestOnvifBean); |
|
||||
String snapshotUrlWsdl = FileUtil.fileReader(new ClassPathResource("digest/GotoPreset.wsdl")); |
|
||||
String wsdl = String.format(snapshotUrlWsdl,profileToken,ballheadPT.getId()); |
|
||||
HttpResponseBean httpResponseBean = RESTClient.getClientConnectionPool() |
|
||||
.postXML(requestUrl, wsdl,requestOnvifBean.getAuth()); |
|
||||
String resultStr = httpResponseBean.getBody(); |
|
||||
if(StringUtils.hasLength(resultStr) && HttpResponseBean.isSuccess(httpResponseBean)) { |
|
||||
return true; |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,17 +0,0 @@ |
|||||
package com.xr.device_car.modules.analysis.entity; |
|
||||
|
|
||||
import lombok.Data; |
|
||||
|
|
||||
@Data |
|
||||
public class BallheadPT { |
|
||||
private String id; |
|
||||
|
|
||||
private String name; |
|
||||
|
|
||||
private String x; |
|
||||
|
|
||||
private String y; |
|
||||
|
|
||||
private String z; |
|
||||
|
|
||||
} |
|
||||
@ -1,12 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"> |
|
||||
<s:Body> |
|
||||
<tptz:AbsoluteMove> |
|
||||
<tptz:ProfileToken>%s</tptz:ProfileToken> |
|
||||
<tptz:Position> |
|
||||
<tt:PanTilt y="%s" x="%s" space="http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace" /> |
|
||||
<tt:Zoom x="%s" space="http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionGenericSpace" /> |
|
||||
</tptz:Position> |
|
||||
</tptz:AbsoluteMove> |
|
||||
</s:Body> |
|
||||
</s:Envelope> |
|
||||
@ -1,6 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"> |
|
||||
<soap:Body> |
|
||||
<tds:GetOnvifInformation /> |
|
||||
</soap:Body> |
|
||||
</soap:Envelope> |
|
||||
@ -1,6 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl"> |
|
||||
<s:Body> |
|
||||
<tptz:GetConfigurations /> |
|
||||
</s:Body> |
|
||||
</s:Envelope> |
|
||||
@ -1,8 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"> |
|
||||
<s:Body> |
|
||||
<tptz:GetPresets> |
|
||||
<tptz:ProfileToken>%s</tptz:ProfileToken> |
|
||||
</tptz:GetPresets> |
|
||||
</s:Body> |
|
||||
</s:Envelope> |
|
||||
@ -1,6 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"> |
|
||||
<soap:Body> |
|
||||
<trt:GetProfiles /> |
|
||||
</soap:Body> |
|
||||
</soap:Envelope> |
|
||||
@ -1,8 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"> |
|
||||
<soap:Body> |
|
||||
<trt:GetSnapshotUri> |
|
||||
<trt:ProfileToken>%s</trt:ProfileToken> |
|
||||
</trt:GetSnapshotUri> |
|
||||
</soap:Body> |
|
||||
</soap:Envelope> |
|
||||
@ -1,8 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"> |
|
||||
<s:Body> |
|
||||
<tptz:GetStatus> |
|
||||
<tptz:ProfileToken>%s</tptz:ProfileToken> |
|
||||
</tptz:GetStatus> |
|
||||
</s:Body> |
|
||||
</s:Envelope> |
|
||||
@ -1,25 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"> |
|
||||
<s:Header xmlns:s="http://www.w3.org/2003/05/soap-envelope"> |
|
||||
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> |
|
||||
<wsse:UsernameToken> |
|
||||
<wsse:Username>%s</wsse:Username> |
|
||||
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%s</wsse:Password> |
|
||||
<wsse:Nonce>%s</wsse:Nonce> |
|
||||
<wsu:Created>%s</wsu:Created> |
|
||||
</wsse:UsernameToken> |
|
||||
</wsse:Security> |
|
||||
</s:Header> |
|
||||
<soap:Body> |
|
||||
<GetStreamUri xmlns="http://www.onvif.org/ver10/media/wsdl"> |
|
||||
<StreamSetup> |
|
||||
<!-- Attribute Wild card could not be matched. Generated XML may not be valid. --> |
|
||||
<Stream xmlns="http://www.onvif.org/ver10/schema">RTP-Unicast</Stream> |
|
||||
<Transport xmlns="http://www.onvif.org/ver10/schema"> |
|
||||
<Protocol>%s</Protocol> |
|
||||
</Transport> |
|
||||
</StreamSetup> |
|
||||
<ProfileToken>%s</ProfileToken> |
|
||||
</GetStreamUri> |
|
||||
</soap:Body> |
|
||||
</soap:Envelope> |
|
||||
@ -1,9 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"> |
|
||||
<s:Body> |
|
||||
<tptz:GotoPreset> |
|
||||
<tptz:ProfileToken>%s</tptz:ProfileToken> |
|
||||
<tptz:PresetToken>%s</tptz:PresetToken> |
|
||||
</tptz:GotoPreset> |
|
||||
</s:Body> |
|
||||
</s:Envelope> |
|
||||
@ -1,19 +1,38 @@ |
|||||
package com.xr.device; |
package com.xr.device; |
||||
|
|
||||
|
import com.xr.device.netty.NettyServer; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.boot.CommandLineRunner; |
||||
import org.springframework.boot.SpringApplication; |
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; |
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; |
||||
import org.springframework.cloud.openfeign.EnableFeignClients; |
import org.springframework.cloud.openfeign.EnableFeignClients; |
||||
|
import org.springframework.scheduling.annotation.Async; |
||||
|
import org.springframework.scheduling.annotation.EnableAsync; |
||||
import org.springframework.scheduling.annotation.EnableScheduling; |
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
|
|
||||
@EnableScheduling//开启定时任务
|
@EnableScheduling//开启定时任务
|
||||
@SpringBootApplication |
@SpringBootApplication |
||||
@EnableDiscoveryClient |
@EnableDiscoveryClient |
||||
@EnableFeignClients |
@EnableFeignClients |
||||
public class DeviceGatherApplication { |
@EnableAsync//开启异步
|
||||
|
public class DeviceGatherApplication implements CommandLineRunner { |
||||
|
|
||||
|
private final NettyServer nettyServer; |
||||
|
|
||||
|
@Autowired |
||||
|
public DeviceGatherApplication(NettyServer nettyServer) { |
||||
|
this.nettyServer = nettyServer; |
||||
|
} |
||||
|
|
||||
public static void main(String[] args) { |
public static void main(String[] args) { |
||||
SpringApplication.run(DeviceGatherApplication.class, args); |
SpringApplication.run(DeviceGatherApplication.class, args); |
||||
} |
} |
||||
|
|
||||
|
@Async |
||||
|
@Override |
||||
|
public void run(String... args) throws Exception { |
||||
|
nettyServer.start(); |
||||
|
} |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -0,0 +1,60 @@ |
|||||
|
package com.xr.device.netty; |
||||
|
|
||||
|
import com.xr.device.websocket.DeviceWebSocketHandler; |
||||
|
import io.netty.buffer.ByteBuf; |
||||
|
import io.netty.channel.ChannelHandlerContext; |
||||
|
import io.netty.channel.ChannelInboundHandlerAdapter; |
||||
|
import io.netty.util.ReferenceCountUtil; |
||||
|
|
||||
|
public class DeviceHandler extends ChannelInboundHandlerAdapter { |
||||
|
|
||||
|
private final HeartbeatService heartbeatService; |
||||
|
|
||||
|
private final DeviceWebSocketHandler deviceWebSocketHandler; |
||||
|
|
||||
|
public DeviceHandler(HeartbeatService heartbeatService,DeviceWebSocketHandler deviceWebSocketHandler) { |
||||
|
this.heartbeatService = heartbeatService; |
||||
|
this.deviceWebSocketHandler = deviceWebSocketHandler; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void channelActive(ChannelHandlerContext ctx) throws Exception { |
||||
|
heartbeatService.addChannel(ctx.channel()); |
||||
|
super.channelActive(ctx); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
||||
|
heartbeatService.removeChannel(ctx.channel()); |
||||
|
super.channelInactive(ctx); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { |
||||
|
ByteBuf in = (ByteBuf) msg; |
||||
|
try { |
||||
|
String deviceId = ""; // 从消息中提取设备ID
|
||||
|
String data = ""; // 从消息中提取其他数据
|
||||
|
|
||||
|
while (in.isReadable()) { |
||||
|
deviceId += (char) in.readByte(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
// 通过WebSocket实时更新状态
|
||||
|
deviceWebSocketHandler.sendMessageToAll("Device " + deviceId); |
||||
|
|
||||
|
System.out.print(data); |
||||
|
System.out.flush(); |
||||
|
} finally { |
||||
|
ReferenceCountUtil.release(msg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { |
||||
|
cause.printStackTrace(); |
||||
|
ctx.close(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
package com.xr.device.netty; |
||||
|
|
||||
|
import io.netty.channel.Channel; |
||||
|
import io.netty.channel.ChannelId; |
||||
|
import io.netty.util.CharsetUtil; |
||||
|
import io.netty.buffer.Unpooled; |
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
|
||||
|
@Service |
||||
|
public class HeartbeatService { |
||||
|
|
||||
|
private final Map<ChannelId, Channel> channels = new ConcurrentHashMap<>(); |
||||
|
|
||||
|
@Scheduled(fixedRate = 5000) |
||||
|
public void sendHeartbeat() { |
||||
|
for (Channel channel : channels.values()) { |
||||
|
if (channel.isOpen()) { |
||||
|
channel.writeAndFlush(Unpooled.copiedBuffer("Heartbeat", CharsetUtil.UTF_8)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void addChannel(Channel channel) { |
||||
|
channels.put(channel.id(), channel); |
||||
|
} |
||||
|
|
||||
|
public void removeChannel(Channel channel) { |
||||
|
channels.remove(channel.id()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
package com.xr.device.netty; |
||||
|
|
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
@Configuration |
||||
|
public class NettyConfig { |
||||
|
|
||||
|
@Bean |
||||
|
public HeartbeatService heartbeatService() { |
||||
|
return new HeartbeatService(); |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
public NettyServer nettyServer(HeartbeatService heartbeatService) { |
||||
|
return new NettyServer(heartbeatService); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
package com.xr.device.netty; |
||||
|
|
||||
|
import io.netty.bootstrap.ServerBootstrap; |
||||
|
import io.netty.channel.ChannelFuture; |
||||
|
import io.netty.channel.ChannelInitializer; |
||||
|
import io.netty.channel.ChannelOption; |
||||
|
import io.netty.channel.EventLoopGroup; |
||||
|
import io.netty.channel.nio.NioEventLoopGroup; |
||||
|
import io.netty.channel.socket.SocketChannel; |
||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel; |
||||
|
|
||||
|
public class NettyServer { |
||||
|
|
||||
|
private final int port = 8520; |
||||
|
private final HeartbeatService heartbeatService; |
||||
|
|
||||
|
public NettyServer(HeartbeatService heartbeatService) { |
||||
|
this.heartbeatService = heartbeatService; |
||||
|
} |
||||
|
|
||||
|
public void start() throws InterruptedException { |
||||
|
EventLoopGroup bossGroup = new NioEventLoopGroup(1); |
||||
|
EventLoopGroup workerGroup = new NioEventLoopGroup(); |
||||
|
|
||||
|
try { |
||||
|
ServerBootstrap bootstrap = new ServerBootstrap(); |
||||
|
bootstrap.group(bossGroup, workerGroup) |
||||
|
.channel(NioServerSocketChannel.class) |
||||
|
.childHandler(new ChannelInitializer<SocketChannel>() { |
||||
|
@Override |
||||
|
protected void initChannel(SocketChannel ch) { |
||||
|
ch.pipeline().addLast(new DeviceHandler(heartbeatService)); |
||||
|
} |
||||
|
}) |
||||
|
.option(ChannelOption.SO_BACKLOG, 128) |
||||
|
.childOption(ChannelOption.SO_KEEPALIVE, true); |
||||
|
|
||||
|
ChannelFuture f = bootstrap.bind(port).sync(); |
||||
|
f.channel().closeFuture().sync(); |
||||
|
} finally { |
||||
|
workerGroup.shutdownGracefully(); |
||||
|
bossGroup.shutdownGracefully(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
package com.xr.device.websocket; |
||||
|
|
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.web.socket.CloseStatus; |
||||
|
import org.springframework.web.socket.WebSocketSession; |
||||
|
import org.springframework.web.socket.handler.TextWebSocketHandler; |
||||
|
import org.springframework.web.socket.TextMessage; |
||||
|
|
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
|
||||
|
@Component |
||||
|
public class DeviceWebSocketHandler extends TextWebSocketHandler { |
||||
|
|
||||
|
private final ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>(); |
||||
|
|
||||
|
@Override |
||||
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception { |
||||
|
sessions.put(session.getId(), session); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { |
||||
|
// 处理来自客户端的消息
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { |
||||
|
sessions.remove(session.getId()); |
||||
|
} |
||||
|
|
||||
|
public void sendMessageToAll(String message) throws Exception { |
||||
|
for (WebSocketSession session : sessions.values()) { |
||||
|
if (session.isOpen()) { |
||||
|
session.sendMessage(new TextMessage(message)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void sendMessageToSession(String sessionId, String message) throws Exception { |
||||
|
WebSocketSession session = sessions.get(sessionId); |
||||
|
if (session != null && session.isOpen()) { |
||||
|
session.sendMessage(new TextMessage(message)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
package com.xr.device.websocket; |
||||
|
|
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.web.socket.config.annotation.EnableWebSocket; |
||||
|
import org.springframework.web.socket.config.annotation.WebSocketConfigurer; |
||||
|
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; |
||||
|
|
||||
|
@Configuration |
||||
|
@EnableWebSocket |
||||
|
public class WebSocketConfig implements WebSocketConfigurer { |
||||
|
|
||||
|
private final DeviceWebSocketHandler deviceWebSocketHandler; |
||||
|
|
||||
|
public WebSocketConfig(DeviceWebSocketHandler deviceWebSocketHandler) { |
||||
|
this.deviceWebSocketHandler = deviceWebSocketHandler; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { |
||||
|
registry.addHandler(deviceWebSocketHandler, "/websocket/device"); |
||||
|
} |
||||
|
} |
||||
@ -1,126 +0,0 @@ |
|||||
package com.xr.drone.demo; |
|
||||
|
|
||||
import java.io.IOException; |
|
||||
import java.text.SimpleDateFormat; |
|
||||
|
|
||||
import com.jnrsmcu.sdk.netdevice.IDataListener; |
|
||||
import com.jnrsmcu.sdk.netdevice.LoginData; |
|
||||
import com.jnrsmcu.sdk.netdevice.NodeData; |
|
||||
import com.jnrsmcu.sdk.netdevice.ParamData; |
|
||||
import com.jnrsmcu.sdk.netdevice.ParamIdsData; |
|
||||
import com.jnrsmcu.sdk.netdevice.ParamItem; |
|
||||
import com.jnrsmcu.sdk.netdevice.RSServer; |
|
||||
import com.jnrsmcu.sdk.netdevice.RealTimeData; |
|
||||
import com.jnrsmcu.sdk.netdevice.StoreData; |
|
||||
import com.jnrsmcu.sdk.netdevice.TelecontrolAck; |
|
||||
import com.jnrsmcu.sdk.netdevice.TimmingAck; |
|
||||
import com.jnrsmcu.sdk.netdevice.TransDataAck; |
|
||||
import com.jnrsmcu.sdk.netdevice.WriteParamAck; |
|
||||
|
|
||||
public class Demo { |
|
||||
|
|
||||
public static void main(String[] args) throws IOException, |
|
||||
InterruptedException { |
|
||||
//RSServer rsServer = RSServer.Initiate(2404);// 初始化
|
|
||||
RSServer rsServer = RSServer.Initiate(2404,"C:\\Users\\PC\\Desktop\\JavaSDKV2.2.2\\param.dat"); |
|
||||
rsServer.addDataListener(new IDataListener() {// 添加监听
|
|
||||
@Override |
|
||||
public void receiveTimmingAck(TimmingAck data) {// 校时指令应答处理
|
|
||||
System.out.println("校时应答->设备编号:" + data.getDeviceId() |
|
||||
+ "\t执行结果:" + data.getStatus()); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void receiveTelecontrolAck(TelecontrolAck data) {// 遥控指令应答处理
|
|
||||
System.out.println("遥控应答->设备编号:" + data.getDeviceId() |
|
||||
+ "\t继电器编号:" + data.getRelayId() + "\t执行结果:" |
|
||||
+ data.getStatus()); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void receiveStoreData(StoreData data) {// 已存储数据接收处理
|
|
||||
// 遍历节点数据。数据包括网络设备的数据以及各个节点数据。温湿度数据存放在节点数据中
|
|
||||
for (NodeData nd : data.getNodeList()) { |
|
||||
SimpleDateFormat sdf = new SimpleDateFormat( |
|
||||
"yy-MM-dd HH:mm:ss"); |
|
||||
String str = sdf.format(nd.getRecordTime()); |
|
||||
System.out.println("存储数据->设备地址:" + data.getDeviceId() |
|
||||
+ "\t节点:" + nd.getNodeId() + "\t温度:" + nd.getTem() |
|
||||
+ "\t湿度:" + nd.getHum() + "\t存储时间:" + str); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void receiveRealtimeData(RealTimeData data) {// 实时数据接收处理
|
|
||||
// 遍历节点数据。数据包括网络设备的数据以及各个节点数据。温湿度数据存放在节点数据中
|
|
||||
for (NodeData nd : data.getNodeList()) { |
|
||||
System.out.println("实时数据->设备地址:" + data.getDeviceId() |
|
||||
+ "\t节点:" + nd.getNodeId() + "\t温度:" + nd.getTem() |
|
||||
+ "\t湿度:" + nd.getHum() + "\t经度:" + data.getLng() |
|
||||
+ "\t纬度:" + data.getLat() + "\t坐标类型:" |
|
||||
+ data.getCoordinateType() + "\t继电器状态:" |
|
||||
+ data.getRelayStatus()); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void receiveLoginData(LoginData data) {// 登录数据接收处理
|
|
||||
System.out.println("登录->设备地址:" + data.getDeviceId()); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void receiveParamIds(ParamIdsData data) { |
|
||||
String str = "设备参数编号列表->设备编号:" + data.getDeviceId() |
|
||||
+ "\t参数总数量:" + data.getTotalCount() + "\t本帧参数数量:" |
|
||||
+ data.getCount() + "\r\n"; |
|
||||
for (int paramId : data.getPararmIdList())// 遍历设备中参数id编号
|
|
||||
{ |
|
||||
str += paramId + ","; |
|
||||
} |
|
||||
System.out.println(str); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void receiveParam(ParamData data) { |
|
||||
String str = "设备参数->设备编号:" + data.getDeviceId() + "\r\n"; |
|
||||
|
|
||||
for (ParamItem pararm : data.getParameterList()) { |
|
||||
str += "参数编号:" |
|
||||
+ pararm.getParamId() |
|
||||
+ "\t参数描述:" |
|
||||
+ pararm.getDescription() |
|
||||
+ "\t参数值:" |
|
||||
+ (pararm.getValueDescription() == null ? pararm |
|
||||
.getValue() : pararm.getValueDescription() |
|
||||
.get(pararm.getValue())) + "\r\n"; |
|
||||
} |
|
||||
System.out.println(str); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void receiveWriteParamAck(WriteParamAck data) { |
|
||||
String str = "下载设备参数->设备编号:" + data.getDeviceId() + "\t参数数量:" |
|
||||
+ data.getCount() + "\t" |
|
||||
+ (data.isSuccess() ? "下载成功" : "下载失败"); |
|
||||
System.out.println(str); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void receiveTransDataAck(TransDataAck data) { |
|
||||
String str = "数据透传->设备编号:" + data.getDeviceId() + "\t响应结果:" |
|
||||
+ data.getData() + "\r\n字节数:" + data.getTransDataLen(); |
|
||||
System.out.println(str); |
|
||||
|
|
||||
} |
|
||||
}); |
|
||||
rsServer.start(); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -0,0 +1,93 @@ |
|||||
|
package com.xr.drone.ntp; |
||||
|
|
||||
|
import org.apache.commons.net.ntp.NTPUDPClient; |
||||
|
import org.apache.commons.net.ntp.TimeInfo; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.net.DatagramPacket; |
||||
|
import java.net.DatagramSocket; |
||||
|
import java.net.InetAddress; |
||||
|
import java.nio.ByteBuffer; |
||||
|
import java.time.Instant; |
||||
|
import java.time.ZoneOffset; |
||||
|
import java.time.ZonedDateTime; |
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
@Service |
||||
|
public class NtpService implements Runnable { |
||||
|
|
||||
|
private static final int NTP_PORT = 1123; |
||||
|
private static final long NTP_TIMESTAMP_OFFSET = 2208988800L; |
||||
|
|
||||
|
public void start() { |
||||
|
new Thread(this).start(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void run() { |
||||
|
try (DatagramSocket socket = new DatagramSocket(NTP_PORT)) { |
||||
|
byte[] buffer = new byte[48]; |
||||
|
while (true) { |
||||
|
DatagramPacket requestPacket = new DatagramPacket(buffer, buffer.length); |
||||
|
socket.receive(requestPacket); |
||||
|
|
||||
|
long currentTime = System.currentTimeMillis() / 1000 + NTP_TIMESTAMP_OFFSET; |
||||
|
ByteBuffer responseBuffer = ByteBuffer.allocate(48); |
||||
|
Arrays.fill(responseBuffer.array(), (byte) 0); |
||||
|
|
||||
|
responseBuffer.put(0, (byte) 0x24); // LI, Version, Mode
|
||||
|
responseBuffer.put(1, (byte) 1); // Stratum
|
||||
|
responseBuffer.put(2, (byte) 0); // Poll
|
||||
|
responseBuffer.put(3, (byte) -20); // Precision
|
||||
|
|
||||
|
responseBuffer.putInt(4, 0); // Root Delay
|
||||
|
responseBuffer.putInt(8, 0); // Root Dispersion
|
||||
|
responseBuffer.putInt(12, 0x4C4F434C); // Reference Identifier ("LOCL")
|
||||
|
|
||||
|
responseBuffer.putLong(16, currentTime << 32); // Reference Timestamp
|
||||
|
responseBuffer.putLong(24, ByteBuffer.wrap(requestPacket.getData(), 40, 8).getLong()); // Originate Timestamp
|
||||
|
responseBuffer.putLong(32, currentTime << 32); // Receive Timestamp
|
||||
|
responseBuffer.putLong(40, currentTime << 32); // Transmit Timestamp
|
||||
|
|
||||
|
DatagramPacket responsePacket = new DatagramPacket( |
||||
|
responseBuffer.array(), |
||||
|
responseBuffer.array().length, |
||||
|
requestPacket.getAddress(), |
||||
|
requestPacket.getPort() |
||||
|
); |
||||
|
socket.send(responsePacket); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
String serverAddress = "192.168.1.83"; // 替换为你的NTP服务器IP
|
||||
|
int port = 1123; // 使用端口1123
|
||||
|
|
||||
|
try { |
||||
|
NTPUDPClient client = new NTPUDPClient(); |
||||
|
client.setDefaultTimeout(10000); |
||||
|
client.open(); |
||||
|
|
||||
|
InetAddress hostAddr = InetAddress.getByName(serverAddress); |
||||
|
TimeInfo info = client.getTime(hostAddr, port); |
||||
|
|
||||
|
// 处理时间信息
|
||||
|
long returnTime = info.getReturnTime(); |
||||
|
long receiveTime = info.getMessage().getReceiveTimeStamp().getTime(); |
||||
|
long transmitTime = info.getMessage().getTransmitTimeStamp().getTime(); |
||||
|
|
||||
|
System.out.println("NTP Server Time: " + receiveTime); |
||||
|
System.out.println("Local Return Time: " + returnTime); |
||||
|
System.out.println("Transmit Time: " + transmitTime); |
||||
|
|
||||
|
client.close(); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("Error: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue