首先了解下socket通讯传输数据的特点:数据在网络传输时使用的都是字节流或字符流,Socket也不例外,所以我们发送数据的时候需要转换为字节发送,读取的时候也是以字节为单位读取。
那么问题就在于socket通讯时,接收方并不知道此次数据有多长,因此无法精确地创建一个缓冲区(字节数组)用来接收,在不定长通讯中,通常使用的方式时每次默认读取8*1024长度的字节,若输入流中仍有数据,则再次读取,一直到输入流没有数据为止。但是如果发送数据过大时,发送方会对数据进行分包发送,这种情况下或导致接收方判断错误,误以为数据传输完成,因而接收不全。
所以,大部分情况下,双方使用socket通讯时都会约定一个定长头放在传输数据的最前端,用以标识数据体的长度,通常定长头有整型int,短整型short,字符串Strinng三种形式。
下面小编介绍两个socket+xml传输的实例,案例一,是使用writeUTF()和readUTF()方法,发送和读取传输的数据。
案例2是组装好xml后,计算xml的字节长度,放在报文头,使用write()方法发送数据,read()方法读取数据。
这里再介绍在writeUTF()和write()方法的区别:
- writeUTF(String str);
- write(int b) ;
案例一 服务端:
package tcpSocket;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class TCPServer2 {
public static void main(String args[]) {
int serverPort = 7896;
ServerSocket listenSocket ;
Socket clientSocket ;
try {
// ******************接收读取客户端传来的内容******************************************
listenSocket = new ServerSocket(serverPort);
clientSocket = listenSocket.accept();
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
String data = in.readUTF();
// System.out.println("接收到的数据:" + data);
DOM(data);
// ******************向客户端写xml文件******************************************
DataOutputStream out=new DataOutputStream(clientSocket.getOutputStream());
// 定义工厂 API,使应用程序能够从 XML 文档获取生成 DOM 对象树的解析器
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
// 定义 API, 使其从 XML 文档获取 DOM 文档实例。使用此类,应用程序员可以从 XML 获取一个 Document
DocumentBuilder builder = factory.newDocumentBuilder();
// Document 接口表示整个 HTML 或 XML 文档。从概念上讲,它是文档树的根,并提供对文档数据的基本访问
Document document = builder.newDocument();
//组织生产xml文件内容
Element root = document.createElement("persons");
document.appendChild(root);
Element person = document.createElement("person");
Element name = document.createElement("name");
name.appendChild(document.createTextNode("java小强"));
person.appendChild(name);
Element sex = document.createElement("sex");
sex.appendChild(document.createTextNode("man"));
person.appendChild(sex);
Element age = document.createElement("age");
age.appendChild(document.createTextNode("99"));
person.appendChild(age);
root.appendChild(person);
TransformerFactory tf = TransformerFactory.newInstance();
// 此抽象类的实例能够将源树转换为结果树
Transformer transformer;
transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transformer.transform(source, new StreamResult(bos));
String xmlStr = bos.toString();
out.writeUTF(xmlStr);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void DOM(String data) {
try {
//遍历xml获取内容
byte[] b = data.getBytes();
InputStream inp = new ByteArrayInputStream(b);
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inp);
NodeList nl = doc.getElementsByTagName("persons");
// System.out.println(nl.getLength());
for (int i = 0; i < nl.getLength(); i++) {
System.out.println("person: "
+ doc.getElementsByTagName("person").item(i)
.getFirstChild().getNodeValue());
System.out.println("name: "
+ doc.getElementsByTagName("name").item(i)
.getFirstChild().getNodeValue());
System.out.println("sex: "
+ doc.getElementsByTagName("sex").item(i)
.getFirstChild().getNodeValue());
System.out.println("age: "
+ doc.getElementsByTagName("age").item(i)
.getFirstChild().getNodeValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端:
package tcpSocket;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class TCPClient {
public static void main(String[] args) throws Exception {
// 2017年12月29日 下午1:43:11
Socket soc = null;
String data = "";
InetAddress addr = InetAddress.getByName("127.0.0.1");
int serverPort = 7896;
if (addr.isReachable(5000)) {
try {
soc = new Socket(addr, serverPort);
//************************向客户端写xml文件******************************************
DataOutputStream out=new DataOutputStream(soc.getOutputStream());
// 定义工厂 API,使应用程序能够从 XML 文档获取生成 DOM 对象树的解析器
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
// 定义 API, 使其从 XML 文档获取 DOM 文档实例。使用此类,应用程序员可以从 XML 获取一个 Document
DocumentBuilder builder = factory.newDocumentBuilder();
// Document 接口表示整个 HTML 或 XML 文档。从概念上讲,它是文档树的根,并提供对文档数据的基本访问
Document document = builder.newDocument();
//组织生产xml文件内容
Element root = document.createElement("persons");
document.appendChild(root);
Element person = document.createElement("person");
Element name = document.createElement("name");
name.appendChild(document.createTextNode("java小强"));
person.appendChild(name);
Element sex = document.createElement("sex");
sex.appendChild(document.createTextNode("man"));
person.appendChild(sex);
Element age = document.createElement("age");
age.appendChild(document.createTextNode("99"));
person.appendChild(age);
root.appendChild(person);
TransformerFactory tf = TransformerFactory.newInstance();
// 此抽象类的实例能够将源树转换为结果树
Transformer transformer;
transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transformer.transform(source, new StreamResult(bos));
String xmlStr = bos.toString();
out.writeUTF(xmlStr);
//********************************接收读取客户端传来的内容******************************************
//接收来自服务器的数据,并解析打印
DataInputStream in = new DataInputStream(soc.getInputStream());
data = in.readUTF();
// System.out.println("接收到的数据:" + data);
DOM(data);
} catch (UnknownHostException e) {
System.out.println("Socket Error:" + e.getMessage());
} catch (EOFException e) {
System.out.println("EOF:" + e.getMessage());
} catch (IOException e) {
System.out.println("IO:" + e.getMessage());
} finally {
if (soc != null)
try {
soc.close();
} catch (IOException e) {/* close failed */
}
}
} else {
System.out.println("FAILURE - ping " + addr
+ " with no interface specified");
}
}
public static void DOM(String data) {
try {
byte[] b = data.getBytes();
InputStream inp = new ByteArrayInputStream(b);
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inp);
NodeList nl = doc.getElementsByTagName("persons");
// System.out.println(nl.getLength());
for (int i = 0; i < nl.getLength(); i++) {
System.out.println("person: "
+ doc.getElementsByTagName("person").item(i)
.getFirstChild().getNodeValue());
System.out.println("name: "
+ doc.getElementsByTagName("name").item(i)
.getFirstChild().getNodeValue());
System.out.println("sex: "
+ doc.getElementsByTagName("sex").item(i)
.getFirstChild().getNodeValue());
System.out.println("age: "
+ doc.getElementsByTagName("age").item(i)
.getFirstChild().getNodeValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
用到的jar包可见:http://download.csdn.net/download/csdnliuxin123524/10180445
案例二,
客户端,
package socket;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import org.apache.commons.lang.StringUtils;
public class CallExtPboc {
@SuppressWarnings("resource")
public static void main(String[] args) throws Exception {
Socket soc = null;
String data = "";
InetAddress addr = InetAddress.getByName("127.0.0.1");
int serverPort = 7896;
soc = new Socket(addr, serverPort);
DataOutputStream out=new DataOutputStream(soc.getOutputStream());
String xmlReq = builderReqXml();
byte[] b = xmlReq.getBytes("UTF-8");
long len=b.length;
String length=String.format("%06d",len);
xmlReq = length+xmlReq;
byte[] bt = xmlReq.getBytes("utf-8");
out.write(bt);
// out.writeUTF(builderReqXml());
//接收来自服务器的字节类型数据,并解析打印
//DataInputStream in = new DataInputStream(soc.getInputStream());
//byte[] buf =new byte[1024];
//int readb=in.read(buf);
//System.out.println("**************************************");
//if(readb != -1){
// System.out.println(new String(buf,0,readb));
//}
//in.close();
}
private static String builderReqXml(){
StringBuffer xmlReq = new StringBuffer();
// xmlReq.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
xmlReq.append("<SERVICE xmlns=\"http://www.sss.com/dataspec/\">");
//构造SERVICE_HEADER节点里面的数据
StringBuilder serviceHeader = new StringBuilder();
serviceHeader.append(getNode("SERVICE_SN","198234712374-17412748"));
serviceHeader.append(getNode("SERVICE_ID","12100"));//交易码
serviceHeader.append(getNode("ORG","org1"));
serviceHeader.append(getNode("CHANNEL_ID","01"));//服务渠道编号----请求渠道
serviceHeader.append(getNode("OP_ID","tt"));
serviceHeader.append(getNode("REQUST_TIME","20050621123000"));
serviceHeader.append(getNode("VERSION_ID","01"));
serviceHeader.append("<MAC/>");
//将SERVICE_HEADER节点数据加入报文中
xmlReq.append(getNode("SERVICE_HEADER", serviceHeader.toString()));
//构造SERVICE_BODY节点里面的数据
StringBuilder serviceBody = new StringBuilder();
//构造extAttributes节点的数据
StringBuffer extAttributes =new StringBuffer();
//构造auth节点数据
StringBuffer auth =new StringBuffer();
auth.append(getNode("Q_PIN", "0123456789ABCDEF"));
//将auth节点加入到EXT_ATTRIBUTES中
extAttributes.append(getNode("AUTH", auth.toString()));
//将extAttributes节点加入到SERVICE_BODY中
serviceBody.append(getNode("EXT_ATTRIBUTES", extAttributes.toString()));
//构造REQUEST节点里面的数据
StringBuilder request = new StringBuilder();
request.append(getNode("SYS_ID","aps"));
request.append(getNode("OPERATOR_ID", "tt"));
request.append(getNode("ID_NO", "123"));
request.append(getNode("ID_TYPE", "I"));
request.append(getNode("NAME", "czy"));
//将REQUEST节点数据加入至SERVICE_BODY中
serviceBody.append(getNode("REQUEST", request.toString()));
//将SERVICE_BODY节点数据加入至报文中EXT_ATTRIBUTES
xmlReq.append(getNode("SERVICE_BODY", serviceBody.toString()));
xmlReq.append("</SERVICE>");
System.out.println(xmlReq);
return xmlReq.toString();
}
/**
* 根据节点名称以及节点内容,返回节点字符串
* @param nodeName 节点名称
* @param nodeValue 节点内容
* @return 构造出的节点字符串
*/
private static String getNode(String nodeName,String nodeValue){
StringBuilder node = new StringBuilder();
if(!StringUtils.isEmpty(nodeName)){
node.append("<"+nodeName+">");
if(!StringUtils.isEmpty(nodeValue)){
node.append(nodeValue);
}
node.append("</"+nodeName+">");
}
return node.toString();
}
}
这里的xml数据也可以不使用dom4j组装,直接使用字符串拼接如下:客户端
package test.s;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class CallApsService {
private Socket s;
private DataOutputStream out;
public CallApsService() throws IOException {
}
public static void main(String[] args) throws Exception {
CallApsService c = new CallApsService();
int i = 0;
Map<String, String> infoMap = initInput();
for(Entry<String, String> enty: infoMap.entrySet()){
i++;
c.talk(enty.getKey(),enty.getValue(),i);
System.out.println("发送信息完毕!");
}
}
// 发送对象
// ObjectOutputStream oos;
// TransferObj obj;
public void sendMessage(Socket s,String idNo,String name,int i) {
try {
// socket传字符串
out = new DataOutputStream(s.getOutputStream());
//批次号申请
String xmlReq = "<SERVICE xmlns=\"http://www.asss.com/dataspec/\"><SERVICE_HEADER><SERVICE_SN>198234712374-17412748</SERVICE_SN><SERVICE_ID>12100</SERVICE_ID><ORG>org1</ORG><CHANNEL_ID>01</CHANNEL_ID><OP_ID>tt</OP_ID><REQUST_TIME>20050621123000</REQUST_TIME><VERSION_ID>01</VERSION_ID><MAC/></SERVICE_HEADER><SERVICE_BODY><EXT_ATTRIBUTES><AUTH><Q_PIN>0123456789ABCDEF</Q_PIN></AUTH></EXT_ATTRIBUTES><REQUEST><SYS_ID>aps</SYS_ID><OPERATOR_ID>tt</OPERATOR_ID><ID_NO>123</ID_NO><ID_TYPE>I</ID_TYPE><NAME>czy</NAME></REQUEST></SERVICE_BODY></SERVICE>";
String lenthEncode = "UTF-8";
long len = xmlReq.getBytes(lenthEncode).length;
String length=String.format("%06d",len);
xmlReq = length+ xmlReq;
byte[] bt = xmlReq.getBytes(lenthEncode);
out.write(bt);
} catch (IOException e) {
e.printStackTrace();
}
}
public void talk(String idNo,String name,int i) throws Exception {
try {
// 发送对象
s = new Socket("127.0.0.1", 7896);
System.out.println("客户端:发送信息");
sendMessage(s,idNo,name, i);
System.out.println("发送信息完毕!");
// 发字符串
// receiveMessage(s);
out.close();
// in.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (s != null)
s.close(); // 断开连接
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static Map<String, String> initInput(){
Map<String, String> infoMap = new HashMap<String, String>();
infoMap.put("140106198506020369","湘一百二");
return infoMap;
}
}
服务器
package socket;
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class CallExtPbocServer {
public static void main(String[] args) {
int serverPort = 7896;
ServerSocket listenSocket ;
Socket clientSocket ;
try {
// ******************接收读取客户端传来的内容******************************************
listenSocket = new ServerSocket(serverPort);
clientSocket = listenSocket.accept();
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
byte[] buf=new byte[1024];
int tag=in.read(buf);
if(tag!=-1){
System.out.println(new String(buf,0,tag));
}
in.close();
}catch(Exception e){
}
}
}