使用JavaSocket编写发送TCP请求的工具类
2013-06-18 09:30
375 查看
原创:/article/1409302.html
使用JavaSocket编写发送TCP请求的工具类
分类:JavaSE2013-04-11 14:56190人阅读评论(0)收藏举报
javasockettcphttpmina
[java]
view plaincopyprint?
package com.jadyer.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/**
* 使用JavaSocket编写发送TCP请求的工具类
* @see 类似的有一个Mina工具类:http://blog.csdn.net/jadyer/article/details/8088068
* @see 欲查询Scoket的有关属性:http://blog.csdn.net/jadyer/article/details/8788272
* @create Apr 5, 2013 9:25:34 PM
* @author 玄玉<http://blog.csdn.net/jadyer>
*/
public class TCPUtil {
private TCPUtil(){}
/**
* 发送TCP请求
* @see 本方法默认的连接超时和读取超时均为30秒
* @see 编码与解码请求响应字节时,均采用双方约定的字符集,即本方法的第四个参数reqCharset
* @param IP 远程主机地址
* @param port 远程主机端口
* @param reqData 待发送报文的中文字符串形式
* @param reqCharset 该方法与远程主机间通信报文的编码字符集(编码为byte[]发送到Server)
* @return localPort--本地绑定的端口,reqData--请求报文,respData--响应报文,respDataHex--远程主机响应的原始字节的十六进制表示
*/
public static Map<String, String> sendTCPRequest(String IP, String port, String reqData, String reqCharset){
Map<String, String> respMap =
new HashMap<String, String>();
OutputStream out = null;
//写
InputStream in = null;
//读
String localPort = null;
//本地绑定的端口(java socket, client, /127.0.0.1:50804 => /127.0.0.1:9901)
String respData = null;
//响应报文
String respDataHex = null;
//远程主机响应的原始字节的十六进制表示
Socket socket = new Socket();
//客户机
try {
socket.setTcpNoDelay(true);
socket.setReuseAddress(true);
socket.setSoTimeout(30000);
socket.setSoLinger(true,
5);
socket.setSendBufferSize(1024);
socket.setReceiveBufferSize(1024);
socket.setKeepAlive(true);
socket.connect(new InetSocketAddress(IP, Integer.parseInt(port)),
30000);
localPort = String.valueOf(socket.getLocalPort());
/**
* 发送TCP请求
*/
out = socket.getOutputStream();
out.write(reqData.getBytes(reqCharset));
/**
* 接收TCP响应
*/
in = socket.getInputStream();
ByteArrayOutputStream bytesOut =
new ByteArrayOutputStream();
byte[] buffer = new
byte[512];
int len = -1;
while((len=in.read(buffer)) != -1){
bytesOut.write(buffer,
0, len);
}
/**
* 解码TCP响应的完整报文
*/
respData = bytesOut.toString(reqCharset);
respDataHex = formatToHexStringWithASCII(bytesOut.toByteArray());
} catch (Exception e) {
System.out.println("与[" + IP +
":" + port + "]通信遇到异常,堆栈信息如下");
e.printStackTrace();
} finally {
if (null!=socket && socket.isConnected() && !socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
System.out.println("关闭客户机Socket时发生异常,堆栈信息如下");
e.printStackTrace();
}
}
}
respMap.put("localPort", localPort);
respMap.put("reqData", reqData);
respMap.put("respData", respData);
respMap.put("respDataHex", respDataHex);
return respMap;
}
/**
* 通过ASCII码将十进制的字节数组格式化为十六进制字符串
* @see 该方法会将字节数组中的所有字节均格式化为字符串
* @see 使用说明详见<code>formatToHexStringWithASCII(byte[], int, int)</code>方法
*/
private static String formatToHexStringWithASCII(byte[] data){
return formatToHexStringWithASCII(data,
0, data.length);
}
/**
* 通过ASCII码将十进制的字节数组格式化为十六进制字符串
* @see 该方法常用于字符串的十六进制打印,打印时左侧为十六进制数值,右侧为对应的字符串原文
* @see 在构造右侧的字符串原文时,该方法内部使用的是平台的默认字符集,来解码byte[]数组
* @see 该方法在将字节转为十六进制时,默认使用的是<code>java.util.Locale.getDefault()</code>
* @see 详见String.format(String, Object...)方法和new String(byte[], int, int)构造方法
* @param data 十进制的字节数组
* @param offset 数组下标,标记从数组的第几个字节开始格式化输出
* @param length 格式长度,其不得大于数组长度,否则抛出java.lang.ArrayIndexOutOfBoundsException
* @return 格式化后的十六进制字符串
*/
private static String formatToHexStringWithASCII(byte[] data,
int offset, int length){
int end = offset + length;
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
sb.append("\r\n------------------------------------------------------------------------");
boolean chineseCutFlag =
false;
for(int i=offset; i<end; i+=16){
sb.append(String.format("\r\n%04X: ", i-offset));
//X或x表示将结果格式化为十六进制整数
sb2.setLength(0);
for(int j=i; j<i+16; j++){
if(j < end){
byte b = data[j];
if(b >=
0){ //ENG ASCII
sb.append(String.format("%02X ", b));
if(b<32 || b>126){
//不可见字符
sb2.append(" ");
}else{
sb2.append((char)b);
}
}else{ //CHA ASCII
if(j == i+15){
//汉字前半个字节
sb.append(String.format("%02X ", data[j]));
chineseCutFlag =
true;
String s = new String(data, j,
2);
sb2.append(s);
}else
if(j == i&&chineseCutFlag){ //后半个字节
sb.append(String.format("%02X ", data[j]));
chineseCutFlag = false;
String s =
new String(data, j, 1);
sb2.append(s);
}else{
sb.append(String.format("%02X %02X ", data[j], data[j +
1]));
String s =
new String(data, j, 2);
sb2.append(s);
j++;
}
}
}else{
sb.append(" ");
}
}
sb.append("| ");
sb.append(sb2.toString());
}
sb.append("\r\n------------------------------------------------------------------------");
return sb.toString();
}
}
package com.jadyer.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.util.HashMap; import java.util.Map; /** * 使用JavaSocket编写发送TCP请求的工具类 * @see 类似的有一个Mina工具类:http://blog.csdn.net/jadyer/article/details/8088068 * @see 欲查询Scoket的有关属性:http://blog.csdn.net/jadyer/article/details/8788272 * @create Apr 5, 2013 9:25:34 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class TCPUtil { private TCPUtil(){} /** * 发送TCP请求 * @see 本方法默认的连接超时和读取超时均为30秒 * @see 编码与解码请求响应字节时,均采用双方约定的字符集,即本方法的第四个参数reqCharset * @param IP 远程主机地址 * @param port 远程主机端口 * @param reqData 待发送报文的中文字符串形式 * @param reqCharset 该方法与远程主机间通信报文的编码字符集(编码为byte[]发送到Server) * @return localPort--本地绑定的端口,reqData--请求报文,respData--响应报文,respDataHex--远程主机响应的原始字节的十六进制表示 */ public static Map<String, String> sendTCPRequest(String IP, String port, String reqData, String reqCharset){ Map<String, String> respMap = new HashMap<String, String>(); OutputStream out = null; //写 InputStream in = null; //读 String localPort = null; //本地绑定的端口(java socket, client, /127.0.0.1:50804 => /127.0.0.1:9901) String respData = null; //响应报文 String respDataHex = null; //远程主机响应的原始字节的十六进制表示 Socket socket = new Socket(); //客户机 try { socket.setTcpNoDelay(true); socket.setReuseAddress(true); socket.setSoTimeout(30000); socket.setSoLinger(true, 5); socket.setSendBufferSize(1024); socket.setReceiveBufferSize(1024); socket.setKeepAlive(true); socket.connect(new InetSocketAddress(IP, Integer.parseInt(port)), 30000); localPort = String.valueOf(socket.getLocalPort()); /** * 发送TCP请求 */ out = socket.getOutputStream(); out.write(reqData.getBytes(reqCharset)); /** * 接收TCP响应 */ in = socket.getInputStream(); ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); byte[] buffer = new byte[512]; int len = -1; while((len=in.read(buffer)) != -1){ bytesOut.write(buffer, 0, len); } /** * 解码TCP响应的完整报文 */ respData = bytesOut.toString(reqCharset); respDataHex = formatToHexStringWithASCII(bytesOut.toByteArray()); } catch (Exception e) { System.out.println("与[" + IP + ":" + port + "]通信遇到异常,堆栈信息如下"); e.printStackTrace(); } finally { if (null!=socket && socket.isConnected() && !socket.isClosed()) { try { socket.close(); } catch (IOException e) { System.out.println("关闭客户机Socket时发生异常,堆栈信息如下"); e.printStackTrace(); } } } respMap.put("localPort", localPort); respMap.put("reqData", reqData); respMap.put("respData", respData); respMap.put("respDataHex", respDataHex); return respMap; } /** * 通过ASCII码将十进制的字节数组格式化为十六进制字符串 * @see 该方法会将字节数组中的所有字节均格式化为字符串 * @see 使用说明详见<code>formatToHexStringWithASCII(byte[], int, int)</code>方法 */ private static String formatToHexStringWithASCII(byte[] data){ return formatToHexStringWithASCII(data, 0, data.length); } /** * 通过ASCII码将十进制的字节数组格式化为十六进制字符串 * @see 该方法常用于字符串的十六进制打印,打印时左侧为十六进制数值,右侧为对应的字符串原文 * @see 在构造右侧的字符串原文时,该方法内部使用的是平台的默认字符集,来解码byte[]数组 * @see 该方法在将字节转为十六进制时,默认使用的是<code>java.util.Locale.getDefault()</code> * @see 详见String.format(String, Object...)方法和new String(byte[], int, int)构造方法 * @param data 十进制的字节数组 * @param offset 数组下标,标记从数组的第几个字节开始格式化输出 * @param length 格式长度,其不得大于数组长度,否则抛出java.lang.ArrayIndexOutOfBoundsException * @return 格式化后的十六进制字符串 */ private static String formatToHexStringWithASCII(byte[] data, int offset, int length){ int end = offset + length; StringBuilder sb = new StringBuilder(); StringBuilder sb2 = new StringBuilder(); sb.append("\r\n------------------------------------------------------------------------"); boolean chineseCutFlag = false; for(int i=offset; i<end; i+=16){ sb.append(String.format("\r\n%04X: ", i-offset)); //X或x表示将结果格式化为十六进制整数 sb2.setLength(0); for(int j=i; j<i+16; j++){ if(j < end){ byte b = data[j]; if(b >= 0){ //ENG ASCII sb.append(String.format("%02X ", b)); if(b<32 || b>126){ //不可见字符 sb2.append(" "); }else{ sb2.append((char)b); } }else{ //CHA ASCII if(j == i+15){ //汉字前半个字节 sb.append(String.format("%02X ", data[j])); chineseCutFlag = true; String s = new String(data, j, 2); sb2.append(s); }else if(j == i&&chineseCutFlag){ //后半个字节 sb.append(String.format("%02X ", data[j])); chineseCutFlag = false; String s = new String(data, j, 1); sb2.append(s); }else{ sb.append(String.format("%02X %02X ", data[j], data[j + 1])); String s = new String(data, j, 2); sb2.append(s); j++; } } }else{ sb.append(" "); } } sb.append("| "); sb.append(sb2.toString()); } sb.append("\r\n------------------------------------------------------------------------"); return sb.toString(); } }
下面是测试代码
[java]
view plaincopyprint?
public static
void main(String[] args) {
String reqData = "0003721000510110199201209222240000020120922000069347814303000700000813``中国联通交费充值`为号码18655228826交费充值100.00元`UDP1209222238312219411`10000```20120922`chinaunicom-payFeeOnline`UTF-8`20120922223831`MD5`20120922020103806276`1`02`10000`20120922223954`20120922`BOCO_B2C```http://192.168.20.2:5545/ecpay/pay/elecChnlFrontPayRspBackAction.action`1`立即支付,交易成功`";
String IP = "127.0.0.1";
String port = "9901";
String reqCharset = "GB18030";
Map<String, String> respMap = sendTCPRequest(IP, port, reqData, reqCharset);
System.out.println("=============================================================================");
System.out.println("请求报文如下");
System.out.println(respMap.get("reqData"));
System.out.println("=============================================================================");
System.out.println("响应报文如下");
System.out.println(respMap.get("respData"));
System.out.println("=============================================================================");
System.out.println("响应十六进制如下");
System.out.println(respMap.get("respDataHex"));
System.out.println("=============================================================================");
}
public static void main(String[] args) { String reqData = "0003721000510110199201209222240000020120922000069347814303000700000813``中国联通交费充值`为号码18655228826交费充值100.00元`UDP1209222238312219411`10000```20120922`chinaunicom-payFeeOnline`UTF-8`20120922223831`MD5`20120922020103806276`1`02`10000`20120922223954`20120922`BOCO_B2C```http://192.168.20.2:5545/ecpay/pay/elecChnlFrontPayRspBackAction.action`1`立即支付,交易成功`"; String IP = "127.0.0.1"; String port = "9901"; String reqCharset = "GB18030"; Map<String, String> respMap = sendTCPRequest(IP, port, reqData, reqCharset); System.out.println("============================================================================="); System.out.println("请求报文如下"); System.out.println(respMap.get("reqData")); System.out.println("============================================================================="); System.out.println("响应报文如下"); System.out.println(respMap.get("respData")); System.out.println("============================================================================="); System.out.println("响应十六进制如下"); System.out.println(respMap.get("respDataHex")); System.out.println("============================================================================="); }
下面是控制台输出
[java]
view plaincopyprint?
//控制台输出如下
//=============================================================================
// 请求报文如下
// 0003721000510110199201209222240000020120922000069347814303000700000813``中国联通交费充值`为号码18655228826交费充值100.00元`UDP1209222238312219411`10000```20120922`chinaunicom-payFeeOnline`UTF-8`20120922223831`MD5`20120922020103806276`1`02`10000`20120922223954`20120922`BOCO_B2C```http://192.168.20.2:5545/ecpay/pay/elecChnlFrontPayRspBackAction.action`1`立即支付,交易成功`
// =============================================================================
// 响应报文如下
// 00015800000000订单结果通知:商户系统未成功接收到通知,需要继续通知 6717356649614827173120130405201628201304051`
// =============================================================================
// 响应十六进制如下
//
// ------------------------------------------------------------------------
// 0000: 30 30 30 31 35 38 30 30 30 30 30 30 30 30 B6 A9 | 00015800000000订
// 0010: B5 A5 BD E1 B9 FB CD A8 D6 AA 3A C9 CC BB A7 CF | 单结果通知:商户系
// 0020: B5 CD B3 CE B4 B3 C9 B9 A6 BD D3 CA D5 B5 BD CD | ?统未成功接收到通
// 0030: A8 D6 AA 2C D0 E8 D2 AA BC CC D0 F8 CD A8 D6 AA | ?知,需要继续通知
// 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
// 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
// 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
// 0070: 00 00 36 37 31 37 33 35 36 36 34 39 36 31 34 38 | 67173566496148
// 0080: 32 37 31 37 33 31 32 30 31 33 30 34 30 35 32 30 | 2717312013040520
// 0090: 31 36 32 38 32 30 31 33 30 34 30 35 31 60 | 1628201304051`
// ------------------------------------------------------------------------
// =============================================================================
//
相关文章推荐
- 使用JavaSocket编写发送TCP请求的工具类
- 使用JavaSocket编写发送HTTP_POST请求的工具类
- 使用JavaSocket编写发送TCP请求的工具类
- 使用Java原生API编写发送HTTP_POST请求的工具类
- 【使用Java原生API编写发送HTTP_POST请求的工具类】
- 使用Java原生API编写发送HTTP_POST请求的工具类
- 使用java编写一个定期发送邮件通知的工具类
- 使用Java原生API编写发送HTTP_POST请求的工具类
- 使用php的socket发送tcp请求
- nodejs使用http模块发送get与post请求的方法示例
- Http学习之使用HttpURLConnection发送post请求深入
- 使用winpcap定制TCP包发送
- 使用withCredentials发送跨域请求凭据
- Xcode7 使用NSURLSession发送HTTP请求的问题
- 使用Java发送POST、GET请求
- jmeter测试TCP服务器/模拟发送TCP请求
- 使用firefox插件httperrequest,模拟发送及接收Json请求
- Android开发中使用Volley框架发送请求的get和post方法
- Android开发使用POST方式向服务器请求和发送数据
- iOS开发网络篇—发送GET和POST请求(使用NSURLSession)