`
pengjianf_ah
  • 浏览: 8693 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

java socket调用webservice以及如何解决连接重置报错问题

阅读更多
一、写这篇记录的原因:
最近看了一些关于关于socket模拟文件服务器的文章或者视频,客户端通过浏览器访问,服务端通过socket去实现,学习之下了解到就是向socket发送制定格式的内容【http协议】,然后服务端进行解析,返回相关的数据,于是就想肯定要可以使用socket模拟调用webservice【webservice就是http协议+soap报文通过tcp协议来传输】,当然了使用httpclient去模拟发送get/post请求最方便,不过也是自己对http协议深入理解【原来的理解就知道http协议是什么样的,但是具体发送的啥内容也模糊】

二、直接贴代码:
1.调用部分
package com.pjf.netbase;

import com.pjf.netentity.Response;
import com.pjf.netservice.ClientService;

public class WebServiceClient {
	public final static int BYTELEN = 1024;// 经测试64个字节以上没有问题

	public static void main(String[] args) throws Exception {

		// BufferedReader br=new BufferedReader(new InputStreamReader(new
		// FileInputStream("1.txt")));
		// String str="";
		// while((str=br.readLine())!=null){
		// System.out.println(str);
		//
		// }
		//
		long startTime = System.currentTimeMillis();
		System.out.println();
		// Socket socket = new Socket("www.webxml.com.cn", 80);
		// PrintWriter pw = new PrintWriter(socket.getOutputStream());
		String req = /*
						 * "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
						 */ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n"
				+ "<soap:Body>\r\n" + "<getSupportCity xmlns=\"http://WebXml.com.cn/\">\r\n"
				+ "<byProvinceName>安徽</byProvinceName>\r\n" + "</getSupportCity>\r\n" + "</soap:Body>\r\n"
				+ "</soap:Envelope>\r\n";

		String head = "POST /WebServices/WeatherWebService.asmx HTTP/1.1\r\n" + "Host: www.webxml.com.cn\r\n"
				+ "Content-Type: text/xml; charset=utf-8\r\n" + "Content-Length:" + req.getBytes().length + "\r\n"
				+ "SOAPAction: \"http://WebXml.com.cn/getSupportCity\"\r\n\r\n";

		Response res = ClientService.callWebService(head, req, "www.webxml.com.cn", 80);
		if (res.getStatus().equals("999")) {
			System.out.println("连接异常,请检查连接");
		} else {
			System.out.println(res.toString());
		}

		// System.out.println(head + str);
		// pw.println(head + str);
		// pw.flush();

		// // 接受客户端的响应
		// byte[] b = new byte[BYTELEN];
		// byte[] context = null;
		// byte[] headbyte = null;
		// InputStream is = socket.getInputStream();
		// int len = 0;
		//
		// int start_position = 0;
		// int end_position = 0;
		// int contlen = 0;
		// boolean isContinue = true;
		// while ((len = is.read(b)) != -1) {
		// System.out.println("每次读取的长度:" + len);
		// // 解析内容
		// if (isContinue) {
		// // 针对头部信息,防止制定的字节一个byte[len]你不够,此处进行字节数组拼接
		// if (headbyte == null) {
		// headbyte = new byte[len];
		// System.arraycopy(b, 0, headbyte, 0, len);
		//
		// } else {
		// byte[] tmp = new byte[headbyte.length + len];
		// System.arraycopy(headbyte, 0, tmp, 0, headbyte.length);
		// System.arraycopy(b, 0, tmp, headbyte.length, len);
		// headbyte = tmp;
		// b = tmp;
		//
		// }
		//
		// for (int i = start_position; i < b.length; i++) {
		// if (b[i] == '\r') {
		// end_position = i;
		// String data = new String(b, start_position, end_position -
		// start_position);
		// if (data.contains("Content-Length")) {
		// // System.out.println("----contlen"+data);
		// contlen = Integer.parseInt(data.split(" ")[1]);
		// }
		//
		// System.out.println("每次读取输出的内容:" + data);
		// start_position = i + 2;
		// i = i + 1;
		// if (data.equals("")) {
		// isContinue = false;
		// System.out.println("内容准备读取,跳出循环准备全部去读");
		// break;
		// }
		//
		// }
		//
		// }
		// }
		// // 如果头结点已经读取完毕,则进行保留内存的内容结点
		// if (isContinue == false) {
		//
		// if (context == null) {
		// context = new byte[b.length - start_position];
		// if (b.length - start_position > 0) {
		// System.arraycopy(b, start_position, context, 0, b.length -
		// start_position);
		// }
		// // 需要判断是否立即结束 ----针对于一次读完的情况,加入此判断,否则可能存在问题
		// if (len < BYTELEN) {
		// break;
		// }
		// }
		// // } else if (len < BYTELEN) {//bug就出现在这
		// // byte[] tmp = new byte[context.length + len];
		// // System.arraycopy(context, 0, tmp, 0, context.length);
		// // System.arraycopy(b, 0, tmp, context.length, len);
		// // context = tmp;
		// // break;
		// // }
		// else {
		// byte[] tmp = new byte[context.length + len];
		// System.arraycopy(context, 0, tmp, 0, context.length);
		// System.arraycopy(b, 0, tmp, context.length, len);
		// context = tmp;
		// System.out.println((context.length) + "-------------" + contlen);
		// if (context.length == contlen) {// 表示数据读取完毕
		// break;
		// }
		// }
		//
		// }
		//
		// }
		// long endTime = System.currentTimeMillis();
		// System.out.println("使用时间:" + (endTime - startTime));
		// System.out.println(new String(context));
		// System.out.println("处理完毕");
		// pw.close();
		// socket.close();
	}

}



2.Response对象定义
package com.pjf.netentity;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 
 * @author pengjf 作为调用webservice的返回对象封装
 *
 */
public class Response {
	private String status;// 状态
	private String statusNum;
	private String version;

	public Response() {
		status = "-999";
	}

	public String getStatusNum() {
		return statusNum;
	}

	public void setStatusNum(String statusNum) {
		this.statusNum = statusNum;
	}

	public String getVersion() {
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	private Map<String, String> headMap = new HashMap<String, String>();// 头节点
	private String resultSoapXml = "";// 解析内容

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public Map<String, String> getHeadMap() {
		return headMap;
	}

	public void setHeadMap(Map<String, String> headMap) {
		this.headMap = headMap;
	}

	public String getResultSoapXml() {
		return resultSoapXml;
	}

	public void setResultSoapXml(String resultSoapXml) {
		this.resultSoapXml = resultSoapXml;
	}

	@Override
	public String toString() {
		String result = "";
		Iterator iter = headMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			result += entry.getKey() + "-->" + entry.getValue() + "\r\n";
		}

		return status + " " + statusNum + " " + version + "\r\n" + result + "\r\n" + resultSoapXml;
	}
}




3.核心处理部分[调用+解析]
package com.pjf.netservice;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import com.pjf.netentity.Response;

public class ClientService {
	public static int BYTELEN = 1024;

	public static Response callWebService(String head, String request, String host, int port)
			throws UnknownHostException, IOException {

		Socket socket = new Socket(host, port);
		PrintWriter pw = new PrintWriter(socket.getOutputStream());
		pw.println(head + request);
		pw.flush();
		Response res = praseInputStrem(socket);
		pw.close();
		pw = null;
		return res;
	}

	public static Response praseInputStrem(Socket socket) {
		Response res = new Response();
		try {
			long startTime = System.currentTimeMillis();
			// 接受客户端的响应
			byte[] b = new byte[BYTELEN];
			byte[] context = null;
			byte[] headbyte = null;
			InputStream is = socket.getInputStream();
			int len = 0;

			int start_position = 0;
			int end_position = 0;
			int contlen = 0;
			boolean isContinue = true;
			boolean isFirstLine = true;
			while ((len = is.read(b)) != -1) {
				System.out.println("每次读取的长度:" + len);
				// 解析内容
				if (isContinue) {
					// 针对头部信息,防止制定的字节一个byte[len]你不够,此处进行字节数组拼接
					if (headbyte == null) {
						headbyte = new byte[len];
						System.arraycopy(b, 0, headbyte, 0, len);

					} else {
						byte[] tmp = new byte[headbyte.length + len];
						System.arraycopy(headbyte, 0, tmp, 0, headbyte.length);
						System.arraycopy(b, 0, tmp, headbyte.length, len);
						headbyte = tmp;
						b = tmp;

					}

					for (int i = start_position; i < b.length; i++) {
						if (b[i] == '\r') {
							end_position = i;
							String data = new String(b, start_position, end_position - start_position);
							if (isFirstLine) {
								isFirstLine = false;
								System.out.println(data);
								String[] firstLineData = data.trim().split(" ");
								if (firstLineData.length != 3) {
									res.setStatus("999");
									return res;
								} else {
									res.setStatus(firstLineData[2]);
									res.setStatusNum(firstLineData[1]);
									res.setVersion(firstLineData[0]);
								}
							}
							// String data = new String(b, start_position,
							// end_position - start_position);
							if (data.contains("Content-Length")) {
								// System.out.println("----contlen"+data);
								contlen = Integer.parseInt(data.split(" ")[1]);
							}
							if (data.contains(":")) {
								String[] headsplit = data.split(":");
								res.getHeadMap().put(headsplit[0].trim(), headsplit[1].trim());
							}

							System.out.println("每次读取输出的内容:" + data);
							start_position = i + 2;
							i = i + 1;
							if (data.equals("")) {
								isContinue = false;
								System.out.println("内容准备读取,跳出循环准备全部去读");
								break;
							}

						}

					}
				}
				// 如果头结点已经读取完毕,则进行保留内存的内容结点
				if (isContinue == false) {

					if (context == null) {
						context = new byte[b.length - start_position];
						if (b.length - start_position > 0) {
							System.arraycopy(b, start_position, context, 0, b.length - start_position);
						}
						// 需要判断是否立即结束 ----针对于一次读完的情况,加入此判断,否则可能存在问题
						if (len < BYTELEN) {
							break;
						}
					} else {
						byte[] tmp = new byte[context.length + len];
						System.arraycopy(context, 0, tmp, 0, context.length);
						System.arraycopy(b, 0, tmp, context.length, len);
						context = tmp;
						System.out.println((context.length) + "-------------" + contlen);
						if (context.length == contlen) {// 表示数据读取完毕
							break;

						}
					}

				}

			}
			long endTime = System.currentTimeMillis();
			System.out.println("使用时间:" + (endTime - startTime));
			res.setResultSoapXml(new String(context));
			socket.shutdownInput();
			socket.shutdownOutput();
			is.close();
			is = null;
			socket = null;
			System.out.println("处理完毕");
		} catch (IOException e) {
			System.out.println(e);
		}

		return res;
	}

}



三、测试结果:
OK 200 HTTP/1.1
Server-->Microsoft-IIS/6.0
Cache-Control-->private, max-age=0
X-AspNet-Version-->2.0.50727
Content-Length-->838
Date-->Tue, 12 Dec 2017 15
X-Powered-By-->ASP.NET
Content-Type-->text/xml; charset=utf-8

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><getSupportCityResponse xmlns="http://WebXml.com.cn/"><getSupportCityResult><string>合肥 (58321)</string><string>巢湖 (58326)</string><string>蚌埠 (58221)</string><string>安庆 (58424)</string><string>六安 (58311)</string><string>滁州 (58236)</string><string>马鞍山 (58336)</string><string>阜阳 (58203)</string><string>宣城 (58433)</string><string>铜陵 (58429)</string><string>淮北 (58116)</string><string>芜湖 (58334)</string><string>宿州 (58122)</string><string>淮南 (58224)</string><string>池州 (58427)</string></getSupportCityResult></getSupportCityResponse></soap:Body></soap:Envelope>

四、遇见问题





错误内容很明细,就是只能打印出消息头,消息体不能打印,然后过段时间连接重置,报错,当时还怀疑服务器没有返回,使用抓包工具后,发现数据是返回的,然后这个问题就困惑了好几天


关键问题:

read()会返回-1呢?答案是:当TCP通信连接的一方关闭了套接字时。【readLine底层应该也是这个类似方法】

     再次分析改过后的代码,客户端用到了read()返回-1这个条件,而服务端也用到了,只有二者有一方关闭了Socket,另一方的read()方法才会返回-1,而在客户端打印输出前,二者都没有关闭Socket,因此,二者的read()方法都不会返回-1,程序便阻塞在此处,都不往下执行,这便造成了死锁。

基本上确定了:webservice服务端并没有关闭输出的socket输入流,由于我们只是客户端,我们就无法控制了,处理的方式就是:
 
将inputStream流中读取完后【context-length:然后读取这个长度】,之后直接跳出再次读环节就可以了,具体就见代码了,有点小麻烦!!


五、此只是本人深入一点学习http协议吧,如果要模拟http请求建议httpclient,代码有问题,也欢迎大家指正!谢谢!!!

  
  • 大小: 130.2 KB
  • 大小: 28 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics