java实现TCP和HTTP通信

背景

近期公司产品对接外部系统,产品内部提供的接口是接收一个外部推送的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属性的用法,菜鸟教程中解释如图:
java实现TCP和HTTP通信_第1张图片

第一反应我发的是xml报文,理所当然使用text/xml,后来发现postman里面报文头Content-Type属性使用的是text/plain,百度了一下。

text/plain是无格式正文
text/xml忽略xml头所指定编码格式而默认采用us-ascii编码
application/xml会根据xml头指定的编码格式来编码

可能是因为text/xml属性改变了数据编码导致无法识别,改为text/plain成功返回200,得到响应报文,问题得以解决。

你可能感兴趣的:(java,网络通信)