Fork me on GitHub

WebService、Http请求、Socket请求

WebService

定义

一种web程序访问方式,常见协议:SOAP(简单对象访问协议),其实就是Http+XML。利用对象进行数据交互。

请求方法

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * @program:FoundationStudy
 * @Author: zhuyang
 * @Date: 2021/09/07/20:20
 * @Description: WebService服务请求
 */
@Slf4j
public class WebServiceUtils {

    public static String setSoapParam(String xml) throws Exception {
        StringBuilder parm = new StringBuilder(200);
        //包装壳需要根据不同的服务,进行不同的修改  xmlns:web="http://WebService.HisService">
        parm.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://WebService.HisService\">\">\r\n")
                .append("<soapenv:Header/>\r\n")
                .append("<soapenv:Body>\r\n")
                .append("<web:getService>\r\n")
                .append("<web:inValue>")
                .append("<![CDATA[")
                .append(xml)
                .append("]]>")
                .append("</web:inValue>\r\n")
                .append("</web:getService>\r\n")
                .append(" </soapenv:Body>\r\n")
                .append("</soapenv:Envelope>");
        //System.out.println(parm.toString());
        return parm.toString();
    }

    /**
     * description 
     * param [soapHeader 参数, url 地址, host ?]
     * return java.lang.String
     * author zhuyang
     * createTime 2021/9/7 23:13
     **/
    public static String sendDataToWebService(String soapHeader,String url,String host) throws Exception {
        soapHeader = setSoapParam(soapHeader);
        String contentType = "text/xml;charset=UTF-8";
        String SOAPAction = "urn:getService";
        URL u = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) u.openConnection();
        conn.setConnectTimeout(60000);
        conn.setReadTimeout(60000);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setDefaultUseCaches(false);
        /**
         *
         * 设置Host头部来让nginx识别,可以为IP,也可以为域名,也可以不设置,不一定要和url的ip相同
         * 若nginx无法识别,添加下列代码,告诉程序,允许能使用这些限制的头部即可
         * System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
         *
         *
         **/
        conn.setRequestProperty("Host", host);
        conn.setRequestProperty("Content-Type", contentType);
        conn.setRequestProperty("Content-Length", String.valueOf(soapHeader.length()));
        conn.setRequestProperty("SOAPAction", "");
        conn.setRequestMethod("POST");
        //定义输出流
        OutputStream output = conn.getOutputStream();
        if (null != soapHeader) {
            byte[] b = soapHeader.toString().getBytes("utf-8");
            //发送soap请求报文
            output.write(b, 0, b.length);
        }
        output.flush();
        output.close();
        //定义输入流,获取soap响应报文
        InputStream input = conn.getInputStream();
        //需设置编码格式,否则会乱码
        String s = IOUtils.toString(input, "UTF-8");
        input.close();
        System.out.println("输出的xml=" + s);
        Document document = DocumentHelper.parseText(s);
        Element root = document.getRootElement();
        return root.getStringValue();
    }

参考

Http请求

定义

利用TCP/IP协议和json数据格式进行数据传输,现在也开始流行RestFul风格;是应用层协议,主要解决如何包装数据。

1)在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。

2)在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。

由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。

请求方法

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

        public static String sendByPost(String urlString, Object params) {
        Map<String, List<String>> responseMap = new HashMap<String, List<String>>();
        String content = null; // 正文内容
        BufferedReader bfr = null;
        DataOutputStream out = null;
        try {
            URL url = new URL(urlString);

            /** -- 创建URL连接 -- */
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //设置请求方式
            conn.setRequestMethod("POST");
            //设置获取连接时间
            conn.setConnectTimeout(10000);
            //设置阅读时间
            conn.setReadTimeout(10000);

            /** -- 设置通用的请求属性 -- */
            //conn.setRequestProperty("appId", "18151689001");
            /**
             * httpUrlConnection.setDoOutput(true);以后就可以使用conn.getOutputStream().write()
             * httpUrlConnection.setDoInput(true);以后就可以使用conn.getInputStream().read();
             * get请求用不到conn.getOutputStream(),因为参数直接追加在地址后面,因此默认是false。
             * post请求(比如:文件上传)需要往服务区传输大量的数据,这些数据是放在http的body里面的,因此需要在建立连接以后,往服务端写数据。
             * 因为总是使用conn.getInputStream()获取服务端的响应,因此默认值是true。
             */
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //设置请求头
            conn.setRequestProperty("Accept-Charset", "UTF-8");
            //conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.connect();
            OutputStream writer = conn.getOutputStream();
            // 写入请求的字符串
            writer.write((params.toString()).getBytes("UTF-8"));
            writer.flush();
            /** -- 获取所有响应头字段 -- */
            responseMap = conn.getHeaderFields();

            /** -- 读取响应内容 -- */
            bfr = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String s = null;
            StringBuffer sbf = new StringBuffer();
            while ((s = bfr.readLine()) != null) {
                sbf.append(s);
            }
            content = sbf.toString();
        } catch (Exception ex) {
            System.out.println("发送请求错误  -- 错误信息:" + ex.getMessage());
        } finally {
            try {
                if (bfr != null) {
                    bfr.close();
                }
            } catch (Exception ex) {
                System.out.println("关闭流错误  -- 错误信息:" + ex.getMessage());
            }
        }
        return content;
    }

Socket请求

定义

Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。

socket连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉;但是由于各种环境因素可能会是连接断开,比如说:服务器端或客户端主机down了,网络故障,或者两者之间长时间没有数据传输,网络防火墙可能会断开该连接以释放网络资源。所以当一个socket连接中没有数据的传输,那么为了维持连接需要发送心跳消息~具体心跳消息格式是开发者自己定义的。

服务器端

import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;

import static java.util.concurrent.Executors.*;
/**
 * @program:FoundationStudy
 * @Author: zhuyang
 * @Date: 2021/09/03/15:42
 * @Description:
 */
public class SocketServer {

    @Test
     public void socketServer() throws IOException, InterruptedException {
        ExecutorService newCacheThreadPool = newCachedThreadPool();
        //创建Socket服务,监听10000端口
        ServerSocket server = new ServerSocket(51503);
        System.out.println("服务启动");
        while (true){
            //获取一个套接字(阻塞)
            final Socket socket = server.accept();
            System.out.println("来了一个客户端");
            newCacheThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    handler(socket);
                }
            });
        }
    }

    private static void handler(Socket socket) {
        byte[] bytes = new byte[1024];
        try {
            InputStream inputStream = socket.getInputStream();
            String message="";
            while (true){
                //读取数据(阻塞)
                int read = inputStream.read(bytes);
                if(read != -1){
                    message+=new String(bytes,0,read);
                }else {
                    break;
                }
            }
            System.out.println("客户端发送消息:"+message);
            OutputStream out = socket.getOutputStream();
            // 6. 回写数据
          // Thread.sleep(1000*100);
            out.write("我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你我很好,谢谢你hahahahahahhaok 完美".getBytes());
            // 7.关闭资源.
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            System.out.println("socket关闭");
            try {
                if (socket != null)
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端

import org.junit.jupiter.api.Test;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @program:FoundationStudy
 * @Author: zhuyang
 * @Date: 2021/09/03/10:11
 * @Description:
 */
public class SocketClient {

    //默认超时时间一分钟以上 2分钟以内
    public static String socket(String ip, Integer port, String message) throws IOException {
        String info = "";
        BufferedReader bufferedReader = null;
        InputStream inputStream = null;
        PrintWriter printWriter = null;
        OutputStream outputStream = null;
        Socket socket = null;
        long t1=0;
        try {
            t1=System.currentTimeMillis();
            socket = new Socket();
            /**
             *  设置建立链接超时时间
             *  java.net.SocketTimeoutException: connect timed out 建立链接超时
             **/
           socket.connect(new InetSocketAddress(ip,port),10000);
            /**
             *  设置读超时时间
             *  java.net.SocketTimeoutException: Read timed out 设置读超时时间
             **/
            socket.setSoTimeout(3*1000);

            // Socket写超时是基于TCP协议栈的超时重传机制,一般不需要设置write的超时时间,也没有提供这种方法。

            //根据输入输出流和服务端连接
            outputStream = socket.getOutputStream();//获取一个输出流,向服务端发送信息
            printWriter = new PrintWriter(outputStream);//将输出流包装成打印流
            printWriter.write(message);
            printWriter.flush();
            socket.shutdownOutput();//关闭输出流
            inputStream = socket.getInputStream();
            //获取一个输入流,接收服务端的信息
            byte[] content2 = getContent2(inputStream);
            info = new String(content2);
            //关闭相对应的资源
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("connect...."+(System.currentTimeMillis()-t1));
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
            ;
            if (inputStream != null) {
                inputStream.close();
            }
            ;
            if (printWriter != null) {
                printWriter.close();
            }
            ;
            if (outputStream != null) {
                outputStream.close();
            }
            ;
            if (socket != null) {
                socket.close();
            }
            ;
        }
        return info;
    }


    //第二种获取文件内容方式,先把所有内容获取为一个byte数组
    public static byte[] getContent2(InputStream inputStream) throws IOException {

        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
        byte[] temp = new byte[1024];
        int size = 0;
        while ((size = inputStream.read(temp)) != -1) {
            out.write(temp, 0, size);
        }
        inputStream.close();
        byte[] bytes = out.toByteArray();
        return bytes;
    }

    @Test
    public void socketTest() throws IOException {
        String server = socket("127.0.0.1", 51503, "服务端你好吗");
        System.out.println("服务端返回:" + server.substring(26,server.length()-16));
    }
}

Gitee地址

https://gitee.com/zhuayng/foundation-study/tree/develop/JavaBasis/Other/src/main/java/com/yxkj/other/modular/flow/socket

posted @ 2021-05-09 19:18  晨度  阅读(474)  评论(0编辑  收藏  举报