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>

四、遇见问题
[img]http://dl2.iteye.com/upload/attachment/0128/1562/294cb992-161f-3d1a-b0ed-3a6284586dba.jpg[/img]

[img]http://dl2.iteye.com/upload/attachment/0128/1564/dea70c14-e99c-385a-9026-a6a2bc5b8dad.png[/img]


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


关键问题:

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

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

基本上确定了:webservice服务端并没有关闭输出的socket输入流,由于我们只是客户端,我们就无法控制了,处理的方式就是:

将inputStream流中读取完后【context-length:然后读取这个长度】,之后直接跳出再次读环节就可以了,具体就见代码了,有点小麻烦!!


五、此只是本人深入一点学习http协议吧,如果要模拟http请求建议httpclient,代码有问题,也欢迎大家指正!谢谢!!!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值