背景
近期公司产品对接外部系统,产品内部提供的接口是接收一个外部推送的xml报文并返回成功失败,实际情况是我们需要主动去发送请求并得到一个文件路径,我们去取的文件并从文件中取出信息再自己推送到产品中,而对接外部系统需要的是TCP通信,取文件又需要通过流来操作,推送到产品使用的是HTTP通信,而产品设计的时候并没有主动请求的功能,无奈之下只好自己动手研究TCP和HTTP的实现。
TCP通信
模拟实现客户端向服务端发送请求,并且服务端返回信息到客户端进行接收
客户端Demo
import java.io.*;
import java.net.Socket;
public class TcpClientDemo {
public static void main(String[] args) {
String ip = "127.0.0.1";
int port = 9999;
String str = "Hello\n" + "世界";
TCPClient(ip,port,str);
}
public static void TCPClient(String ip , int port , String str){
Socket socket = null;
BufferedWriter out = null;
BufferedReader in = null;
try {
//创建连接用于发送信息
socket = new Socket(ip, port);
//创建使用默认大小的输出缓冲区的缓冲字符输出流。
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write(str+"\n");
out.flush();
System.out.println("向服务器发送信息:\n"+str);
//创建使用默认大小的输入缓冲区的缓冲字符输入流。
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读取数据
String message=null;
System.out.println("收到服务器信息:");
while((message=in.readLine())!=null){
System.out.println(message);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
in.close();
out.close();
socket.close();
} catch (IOException e) {
System.out.println("断开连接异常");
}
}
}
}
服务端Demo
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServerDemo {
public static void main(String[] args) {
TCPServer(9999);
}
public static void TCPServer(int port){
Socket socket = null;
ServerSocket serversocket = null;
BufferedReader in = null;
BufferedWriter out = null;
while (true){
try {
//创建连接用于接收信息
serversocket = new ServerSocket(port);
System.out.println("启动服务器....");
socket = serversocket.accept();
System.out.println("客户端:"+socket.getInetAddress().getLocalHost()+"已连接到服务器");
//创建使用默认大小的输入缓冲区的缓冲字符输入流。
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//获取信息
String message=null;
System.out.println("收到客户端信息:");
while ((message = in.readLine()) != null) {
System.out.println(message);
//创建使用默认大小的输出缓冲区的缓冲字符输出流。
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write(message + "\n");
out.flush();
}
} catch (IOException e) {
System.out.println("断开连接");
}finally {
try {
out.close();
in.close();
socket.close();
serversocket.close();
} catch (IOException e) {
System.out.println("断开连接异常");
}
}
}
}
}
HTTP通信
HTTP请求Demo
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpClientDemo {
public static void main(String[] args) {
String url = "…………";
String str = "…………";
doPost(url, str);
}
public static void doPost(String urlStr,String xmlInfo) {
BufferedWriter out = null;
HttpURLConnection conn = null;
try {
String str;
URL url = new URL(urlStr);
conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setUseCaches(false);
conn.setConnectTimeout(60 * 1000);
conn.setReadTimeout(60 * 1000);
conn.setRequestProperty("Content-Type", "text/plain; charset=UTF-8");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("logType", "base");
conn.connect();
out = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8"));
out.write(xmlInfo);
out.flush();
System.out.println("urlStr=" + urlStr);
System.out.println("xmlInfo=" + xmlInfo);
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
//得到响应流
InputStream inputStream = conn.getInputStream();
//将响应流转换成字符串
String returnLine = getStringFromInputStream(inputStream);
str = "Success,返回码为" + responseCode + ",返回信息为" + "---" + returnLine;
} else {
str = "Error,返回码为" + responseCode + ",返回信息为" + conn.getResponseMessage();
}
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
conn.disconnect();
} catch (IOException e) {
System.out.println("断开连接异常");
}
}
}
//获取返回输入流的信息
private static String getStringFromInputStream(InputStream is) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
is.close();
// 把流中的数据转换成字符串, 采用的编码是: utf-8
String status = baos.toString();
baos.close();
return status;
}
}
在实现HTTP通信的时候比较曲折,我首先是通过postman发的请求,确定发送的报文能够收到响应,并且能够正确返回,然而代码实现的时候一直报错,返回码是400,开始的时候打断点,在创建输入流的时候报错,后来百度看到这两行代码conn.setDoOutput(true); conn.setDoInput(true); 用来设置允许输入输出流使用,加上后还是报400,相同报文和地址在postman上面成功返回,后来对比了下,发现是conn.setRequestProperty(“Content-Type”, “text/plain; charset=UTF-8”); 这行代码出了问题,之前看百度的时候查到Content-Type属性的用法,菜鸟教程中解释如图:
第一反应我发的是xml报文,理所当然使用text/xml,后来发现postman里面报文头Content-Type属性使用的是text/plain,百度了一下。
text/plain是无格式正文
text/xml忽略xml头所指定编码格式而默认采用us-ascii编码
application/xml会根据xml头指定的编码格式来编码
可能是因为text/xml属性改变了数据编码导致无法识别,改为text/plain成功返回200,得到响应报文,问题得以解决。