This commit is contained in:
default
2018-11-01 16:18:11 +08:00
parent 553487baf1
commit 63974e7ad6
12 changed files with 1317 additions and 2 deletions

View File

@@ -0,0 +1,83 @@
package com.nms.socket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import com.jfinal.kit.PropKit;
public class SocketClientServeice extends SocketUtils{
public SocketClientServeice(String ip)throws Exception {
super(ip,Integer.parseInt(PropKit.use("socket.properties").get("socket.port")));
}
public SocketClientServeice(String ip, int port)throws Exception {
super(ip, port);
}
/**
* 创建通讯
*
* @time Feb 29, 2012-5:39:01 PM
*/
private void init() throws Exception {
logger.debug("目标通讯:>" + ip + " 创建开始" );
try {
// -- create SocketFactory
SSLSocketFactory ssf = sSLContext.getSocketFactory();
// -- create socket
socket = (SSLSocket) ssf.createSocket(ip, port);
this.in = socket.getInputStream();
this.out = socket.getOutputStream();
logger.info("create socket success.");
//2014-1-23 hyx 如果建立socket成功但是startHandshake握手失败且未设置超时时间时则会一直阻塞
socket.setSoTimeout(1000*1000); //1000秒
// -- handshake 握手
((SSLSocket) socket).startHandshake();
logger.info("handshake success.");
} catch (Exception e) {
logger.error("Target communication:>" + ip + " create failure" + e);
throw e;
}
}
public void sendInfoToServer(String cmd,String str) throws Exception{
try {logger.info("sendInfoToServer begin"+str );
init();
sendMessage(cmd);
receiveMessage();
sendMessage(str);
receiveMessage();
logger.info("sendInfoToServer end"+str );
// } catch (Exception e) {
// logger.debug("sendInfoToServer 异常:"+str );
// throw e;
} finally {
close();
}
}
public String sendInfoToServer2(String cmd,String str) throws Exception{
try {logger.info("sendInfoToServer begin"+str );
init();
sendMessage(cmd);
receiveMessage();
sendMessage(str);
String result = receiveMessage();
sendMessage(SUCCESS);
logger.info("sendInfoToServer end"+str );
return result;
// } catch (Exception e) {
// logger.debug("sendInfoToServer 异常:"+str );
// throw e;
} finally {
close();
}
}
}

View File

@@ -0,0 +1,536 @@
package com.nms.socket;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.apache.log4j.Logger;
import com.jfinal.kit.PropKit;
/**
* SSL 通讯 工具类
* @date Feb 29, 2012 10:05:50 AM
* @author ZhangGang
*
*/
public abstract class SocketUtils{
//文件传输 临时文件命名后缀
private static final String TEMP_SUFFIX = ".tp";
//SSLContext 重置标识
private static boolean resetSSLContextFlag = false;
//通讯编码方式
private static final String DEFAULT_ENCODING = "utf-8";
//公有密匙库 存放公钥(与其他主机加密通讯对应的密匙)
private static final String SERVER_TRUST =PropKit.use("socket.properties").get("ssl.ts"); //System.getProperty("user.dir")+File.separator+"src\\conf\\ssl" + File.separator + "client_ts";
//私有密匙库 存放私钥(向其他主机发布信息的使用的加密密匙)
private static final String SERVER_STORE = PropKit.use("socket.properties").get("ssl.ks"); //System.getProperty("user.dir")+File.separator+"src\\conf\\ssl" + File.separator + "client_ks";
//密匙库 类型
private static final String KEYSTORE_TYPE = "jceks";
//私有密匙库 密码
private static final String SERVER_STORE_PSW = "client";
//公有密匙库 密码
private static final String SERVER_TRUST_PSW = "client";
//私有密匙 密码
private static final String SERVER_KEY_PSW = "123456";
//加密上下位 类型
private static final String SSL_CONTEXT_TYPE = "TLS";
//日志组件对象
protected static Logger logger = Logger.getLogger(SocketUtils.class);
//Socket 通讯
protected Socket socket = null; //Socket
//字节输出流
protected OutputStream out = null;
//字节输入流
protected InputStream in = null; //读取字符流
//通讯目标主机IP
protected String ip = null;
//通讯目标主机端口
protected Integer port = null ;
//SSL通讯上下文对象
protected static SSLContext sSLContext = getSSLContext();
//缓存字节长度
protected static final int BUFF_SIZE = 1024;
/**
* 通讯正常标识
*/
protected static final String SUCCESS ="success"; //通信操作正常
/**
* 通讯异常或终止标识
*/
protected static final String FAIL ="fail"; //通信操作异常或终止
/**
* 通讯创建
* @param ip 目标主机IP
* @param port 目标主机端口
* @throws Exception
*/
public SocketUtils(String ip,Integer port){
logger.info("客户端通讯建立 TO:> "+ip);
this.ip = ip;
this.port = port;
}
/**
* 通讯创建
* @param client 目标通讯实例
*/
public SocketUtils(Socket client) {
socket = client;
logger.info("服务端通讯建立 From:> "+socket.getInetAddress().getHostAddress());
}
/**
* 创建SSLContext方法
* @time Feb 29, 2012-11:40:24 AM
* @return
*/
public static SSLContext getSSLContext(){
SSLContext ctx = null ;
//- 创建 新的sSLContext 校验
//- reCreateSSLContextFlag 为false 且 sSLContext 不为空时无需创建
if(!resetSSLContextFlag && sSLContext !=null){
return sSLContext;
}
//- 创建 新的sSLContext
try {
System.setProperty("javax.net.ssl.trustStore", SERVER_TRUST);
//-- 初始化私钥证书库
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);
ks.load(new FileInputStream(SERVER_STORE), SERVER_STORE_PSW.toCharArray());//载入keystore
kmf.init(ks, SERVER_KEY_PSW.toCharArray());
//-- 初始化公钥证书库
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore tks = KeyStore.getInstance(KEYSTORE_TYPE);
tks.load(new FileInputStream(SERVER_TRUST), SERVER_TRUST_PSW.toCharArray());//载入keystore
tmf.init(tks);
//-- 初始化SSL通讯上下文对象 和 SSL通讯工厂
ctx = SSLContext.getInstance(SSL_CONTEXT_TYPE);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(),new SecureRandom());
logger.info("证书库载入成功(load keystore success.)");
resetSSLContextFlag = false;
} catch (NoSuchAlgorithmException e) {
logger.error("",e);
} catch (CertificateException e) {
logger.error("",e);
} catch (FileNotFoundException e) {
logger.error("",e);
} catch (IOException e) {
logger.error("",e);
} catch (KeyStoreException e) {
logger.error("",e);
} catch (UnrecoverableKeyException e) {
logger.error("",e);
} catch (KeyManagementException e) {
logger.error("",e);
}finally{
}
return ctx;
}
/**
* 字符流 接收信息
**/
protected void sendMessage(String msg) throws UnsupportedEncodingException {
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out,DEFAULT_ENCODING));
pw.println(msg);
pw.flush();
}
/**
* 字符流 发送信息
*/
protected String receiveMessage()throws UnsupportedEncodingException ,IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(in,DEFAULT_ENCODING));
return br.readLine();
}
/**
* Object 形式 发送信息
*/
protected void sendObject(Object object) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(object);
oos.flush();
}
/**
* Object 形式 接收信息
*/
protected Object receiveObject() throws ClassNotFoundException,IOException{
ObjectInputStream ois = new ObjectInputStream(in);
return ois.readObject();
}
/**
* 字节流 发送单个文件
**/
public void sendFile(File file) throws IOException{
if(file==null ||file.length()==0){
return;
}
FileInputStream fis = null;
try {
//发送文件大小
sendMessage(file.length() + "");
//发送文件内容
int len;
byte[] buff = new byte[BUFF_SIZE];
fis = new FileInputStream(file);
while ((len = fis.read(buff)) != -1) {
//将读取的内容写入文件
out.write(buff, 0, len);
}
out.flush();
// } catch (IOException e) {
// logger.error("单个发送文件失败!\n"+ExceptionPrintUtils.printExceptionStack(e));
} finally{
if(fis!=null){
//try {
fis.close();
fis=null;
//} catch (IOException e) {
//logger.error("",e);
//}
}
}
}
/**
* 字节流 接收单个文件 并保存
*/
protected void receiveFile(String filePath) throws IOException{
FileOutputStream fos = null;
File file = new File(filePath);
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
if(!file.exists()){
file.createNewFile();
}
try {
//接收文件大小
long fileSize = Long.parseLong(receiveMessage());
//接收文件内容
byte[] buff = new byte[BUFF_SIZE];
fos = new FileOutputStream(filePath);
int nRead = 0;
//单个文件循环读取
rfile:while ((nRead = in.read(buff, 0, (int)(BUFF_SIZE<fileSize?BUFF_SIZE:fileSize))) > 0) {
fos.write(buff,0,nRead);
fos.flush();
fileSize -= nRead;
if(fileSize<=0){
break rfile;
}
}
fos.close();
// } catch (IOException e) {
// logger.error("接收文件失败!",e);
}finally{
if(fos!=null){
//try {
fos.close();
fos = null;
//} catch (IOException e) {
// logger.error("",e);
//}
}
}
}
/**
* 批量上传文件
* @param dir 本地文件集合根目录绝对路径
* @param fileList 上传的文件列表
* (DC未使用)
*/
protected void sendFileByBath(String dir, List<File> fileList) {
ObjectOutputStream oos = null;
FileInputStream fis = null;
try {
// 第一步发送本地根目录地址用于地址截取保证fileList的目录结构完整性
this.sendMessage(dir);
String result = this.receiveMessage();
logger.debug("根目录路径通信状态: " + result);
// 第二步 用ObjectOutputStream工具类 发送file对象信息 用于文件名,文件目录,文件大小的获取
oos = new ObjectOutputStream(out);
List<String[]> fileStrList = new ArrayList<String[]>();
for(File f : fileList){
String[] tmpArr = new String[]{
f.getAbsolutePath(), f.length() + ""
};
fileStrList.add(tmpArr);
}
oos.writeObject(fileStrList);
// 第三部,发送文件
byte[] buff = new byte[BUFF_SIZE];
int len = 0;
// 循环上传文件
for (File file : fileList) {
fis = new FileInputStream(file);
while ((len = fis.read(buff)) != -1) {// 将读取的内容输出流
out.write(buff, 0, len);
}
out.flush();
fis.close();
fis = null;
}
logger.debug("多文件上传结束,共 "+(fileList==null ? 0 : fileList.size())+ "个文件");
} catch (IOException e) {
logger.error("Fail to send file",e);
} finally {
try {
if (fis != null) {
fis.close();
fis = null;
}
} catch (IOException e) {
logger.error("",e);
}
}
}
/**
* 批量接收文件 保存为 List<byte[]>形式
* @param newDir
* (DC未使用)
*/
protected LinkedList<byte []> receiveFileBytesByBath() {
LinkedList<byte []> bsList = new LinkedList<byte []>();
ObjectInputStream ois = null;
try {
//获取集合文件路径
String oldDir = this.receiveMessage();
this.sendMessage(SUCCESS);
ois = new ObjectInputStream(in);
List<String[]> fileList = (List<String[]>)ois.readObject();
//循环读取多个文件
if(fileList != null && fileList.size()>0){
for(String[] arr : fileList){
int fileLength = Integer.parseInt(arr[1]); //大小
byte[] buff0 = new byte[fileLength];
byte[] buff = new byte[BUFF_SIZE];
int nRead = 0;
int j = 0;
//单个文件循环读取
rfile:while ((nRead = in.read(buff, 0, (int)(BUFF_SIZE<fileLength?BUFF_SIZE:fileLength))) > 0) {
//将数据存入集合
for(int i = 0 ; i < nRead ; i++){
buff0[j] = buff[i];
j++;
}
logger.debug(j+" "+buff0.length);
fileLength -= nRead;
if(fileLength<=0){
break rfile;
}
}
bsList.add(buff0);
}
}
logger.debug("共接收 "+(fileList==null ? 0 : fileList.size())+ "个文件 存入内存");
} catch (IOException e) {
logger.error("",e);
bsList.clear();
} catch (ClassNotFoundException e) {
logger.error("",e);
bsList.clear();
}
return bsList;
}
/**
* 关闭通讯
* @time Aug 28, 2011-8:35:21 PM
*/
protected void close(){
try {
if(in!=null){in.close();in=null;}
if(out!=null){out.close();out=null;}
if(socket!=null){socket.close();socket=null;}
} catch (IOException e) {
logger.error("",e);
}
}
/**
*
* @time Mar 12, 2012-11:08:43 AM
* @param url
* @return -1文件不存在 0文件长度为0 N文件长度
*/
public static long getRemoteFileSize(String url) {
long size = -1;
try {
HttpURLConnection conn = (HttpURLConnection) (new URL(url)).openConnection();
//请求状态 大于等于400 均为 represent access error
if(conn.getResponseCode() >= 400){
logger.error("HttpURLConnection Error Code:"+conn.getResponseCode());
return -2;
}
//获取ContentLength 并 关闭连接
size = conn.getContentLength();
conn.disconnect();
} catch (Exception e) {
logger.error("",e);
}
return size;
}
/**
* 上传文件时,判断该文件是否已存在,如存在,则在后面加入时间戳
*
* @param fileName
* 单纯的文件名
*/
public static String addTimeTagForFileName(String fileName,boolean isDirectory) {
Calendar calendar = new GregorianCalendar();
long timestamp = calendar.getTimeInMillis();
// 去掉后缀的文件名
String fielType = "";
if (!isDirectory && fileName.lastIndexOf(".") != -1) {
fielType = fileName.substring(fileName.lastIndexOf("."));
fileName = fileName.substring(0, fileName.lastIndexOf("."));
}
fileName += "_" + timestamp+""+((int)(Math.random()*1000));
fileName += fielType;
return fileName;
}
/**
* 获取 断点续传 文件参数信息
* @time Apr 17, 2012-9:56:56 AM
* @param filePath
* @return
*/
// public static FileComment getFileParams(String filePath) throws Exception{
// File file = new File(filePath);
// FileComment fileParam = new FileComment(file.getName(),file.length(),0l,file.exists()?MD5Util.getFileMD5String(file):null);
// if(!file.exists()){
// file = new File(filePath+TEMP_SUFFIX);
// fileParam.setStart(file.length());
// }
// return fileParam;
// }
public static void pl(Object object){
System.out.println(object==null?null:object.toString());
}
}
class TempFile {
private String fileName = null;
private File File = null;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public File getFile() {
return File;
}
public void setFile(File file) {
File = file;
}
}