分享

JavaSocket短连接实现分别接收字符串和16进制数据

 印度阿三17 2019-08-01

做个笔记,在接收16进制数据的时候乱码了。原因是Socket在接收数据的时候需要根据不同的数据定义不同的接收方式,也就是约定好传输协议(具体体现在后面服务端接收16进制那里)。

字符串的发送接收

字符串发送:

字符串接收:

客户端代码:

没什么好说的,复制粘贴导包。

public static void main(String[] args)
    {
        try
        {
            Socket socket = new Socket("localhost", 8888);
            //得到一个输出流,用于向服务器发送数据
            OutputStream outputStream = socket.getOutputStream();
            //将写入的字符编码成字节后写入一个字节流
            OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8");
            System.out.println("请输入数据:");
            while (true)
            {
				Scanner sc = new Scanner(System.in);
                String data = sc.nextLine();
                writer.write(data);
                //刷新缓冲
                writer.flush();
                //只关闭输出流而不关闭连接
                socket.shutdownOutput();
                //获取服务器端的响应数据
                //得到一个输入流,用于接收服务器响应的数据
                InputStream inputStream = socket.getInputStream();
                //字节流以UTF-8的编码转换为字符流
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
                //为输入流添加缓冲
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                System.out.println("客户端IP地址:"   socket.getInetAddress().getHostAddress());
                String info;
                //输出服务器端响应数据
                while ((info = bufferedReader.readLine()) != null)
                {
                    System.out.println("收到来自服务端的信息:"   info);
                }
                //关闭资源
                bufferedReader.close();
                inputStreamReader.close();
                inputStream.close();
                writer.close();
                outputStream.close();
                socket.close();
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

服务端代码:

注意readLine()方法,客户端发送的内容结尾一定要有换行符,不然会一直阻塞导致客户端得不到响应。其它注释里都有。

try
        {
            System.out.println(">>>服务启动,等待终端的连接\n");
            ServerSocket server = new ServerSocket(8888);
            int count = 0;
            while (true)
            {
                //开启监听
                Socket socket = server.accept();
                count  ;
                System.out.println(">>>第"   count   "个终端连接成功");
                ServerThread thread = new ServerThread(socket);
                thread.start();
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
/**
 * 短连接
 */
public class ServerThread extends Thread
{
    private Socket m_socket;

    public ServerThread(Socket socket)
    {
        this.m_socket = socket;
    }

    @Override
    public void run()
    {
        //字节输入流
        InputStream inputStream = null;
        //字节输出流
        OutputStream outputStream = null;
        //字节输入流到字符输入流的转换
        InputStreamReader inputStreamReader = null;
        //加快字符读取速度
        BufferedReader bufferedReader = null;
        //打印输出流
        PrintWriter printWriter = null;
        try
        {
            inputStream = m_socket.getInputStream();
            String info;
            inputStreamReader = new InputStreamReader(inputStream);
            bufferedReader = new BufferedReader(inputStreamReader);
            //注意,readLine()方法如果没有读到报文结束符(换行)会一直阻塞
            while ((info = bufferedReader.readLine()) != null)
            {
                System.out.println(">>>线程"   this.getId()   "收到来自终端的信息:"   info);
            }
            //关闭终端的输入流(不关闭服务端的输出流),此时m_socket虽然没有关闭,但是客户端已经不能再发送消息
            m_socket.shutdownInput();
            //解析终端的信息
            String responseStr = "Null...";
            if (null != info && !"".equals(info))
            {
                //模拟业务处理Thread.sleep(10000);
                responseStr = new MessageReceive().RecevieHexStr(info);
            }
            outputStream = m_socket.getOutputStream();
            printWriter = new PrintWriter(outputStream);
            printWriter.write(responseStr);
            printWriter.flush();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        //关闭资源
        finally
        {
            System.out.println(">>>本次连接已断开\n");
            try
            {
                if (printWriter != null)
                    printWriter.close();
                if (outputStream != null)
                    outputStream.close();
                if (bufferedReader != null)
                    bufferedReader.close();
                if (inputStreamReader != null)
                    inputStreamReader.close();
                if (inputStream != null)
                    inputStream.close();
                if (m_socket != null)
                    m_socket.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

}

 16进制数据的发送接收

客户端代码:无

由Socket测试工具来完成,网上大把,自行下载。

服务端代码:

开头说过使用Socket通信需要约定好协议,否则服务端不知道你客户端内容是否发送完毕,就会一直阻塞。前面的字符串的发送和接收其实也是有协议存在的,这个协议就是字符串和换行符,服务端读取的时候将字节流转为字符流,然后一行行的读取,读到换行符的时候就表示客户端的消息已发送完毕。

但是当客户端发送的是16进制数据的时候,这个时候服务端仍然用读取字符串的方式去处理就会乱码。所以这里采用的方法是将字节流以字节的形式一个一个的读出来,然后每个字节转为16进制的字符串。

byte[] bytes = new byte[1];
while ((dataInputStream.read(bytes)) != -1)
    String tempStr = ConvertUtil.ByteArrayToHexStr(bytes);

同理,也需要一个标识符表示客户端的内容已经发送完毕,否则read()方法也会一直阻塞,导致客户端得不到响应。比如客户端发送内容的末尾加个7E,当服务端读到7E就跳出While循环,但前提是要保证发送内容里面7E是唯一的,如果有其它需要用7E表示的自行转义,然后服务端读取完内容以后再转义回来。

这里我使用的是另外一种方法判断客户端的内容是否发送完毕:InputStream对象的available()方法。

dataInputStream.available()

官方解释:返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。下一个调用可能是同一个线程,也可能是另一个线程。一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数。大白话就是:返回剩余未读长度

至于其它的注释里都有写

/**
 * 短连接
 */
public class ServerThread extends Thread
{
    private Socket m_socket;

    public ServerThread(Socket socket)
    {
        this.m_socket = socket;
    }

    @Override
    public void run()
    {
        //字节输入流
        InputStream inputStream = null;
        //字节输出流
        OutputStream outputStream = null;
        //缓冲输入流
        BufferedInputStream bufferedInputStream = null;
        //数据输入流
        DataInputStream dataInputStream = null;
        //打印输出流
        PrintWriter printWriter = null;
        try
        {
            inputStream = m_socket.getInputStream();
            String info = "";
            bufferedInputStream = new BufferedInputStream(inputStream);
            dataInputStream = new DataInputStream(bufferedInputStream);
            //一次读取一个byte
            byte[] bytes = new byte[1];
            //注意,read()方法如果没有数据会一直阻塞,也就是永远不会等于-1,除非客户端调用close(),如果想在while循环外部获取数据则需要设定跳出条件
            while ((dataInputStream.read(bytes)) != -1)
            {
                String tempStr = ConvertUtil.ByteArrayToHexStr(bytes)   " ";
                info  = tempStr;
                //返回下次调用可以不受阻塞地从此流读取或跳过的估计字节数,如果等于0则表示已经读完
                if (dataInputStream.available() == 0)
                {
                    System.out.println(">>>终端信息读取完毕,最后一位:"   tempStr);
                    break;
                }
            }
            System.out.println(">>>线程"   this.getId()   "收到来自终端的信息:"   info);
            //关闭终端的输入流(不关闭服务端的输出流),此时m_socket虽然没有关闭,但是客户端已经不能再发送消息
            m_socket.shutdownInput();
            //解析终端的信息
            String responseStr = "Null...";
            //模拟业务处理
            Thread.sleep(10000);
            outputStream = m_socket.getOutputStream();
            printWriter = new PrintWriter(outputStream);
            printWriter.write(responseStr);
            printWriter.flush();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        //关闭资源
        finally
        {
            System.out.println(">>>本次连接已断开\n");
            try
            {
                if (printWriter != null)
                    printWriter.close();
                if (outputStream != null)
                    outputStream.close();
                if (inputStream != null)
                    inputStream.close();
                if (bufferedInputStream != null)
                    bufferedInputStream.close();
                if (dataInputStream != null)
                    dataInputStream.close();
                if (m_socket != null)
                    m_socket.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

}
自定义的转换类:
/**
     * 普通byte[]转16进制Str
     *
     * @param array
     */
    public static String ByteArrayToHexStr(byte[] array)
    {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < array.length; i  )
        {
            String hex = Integer.toHexString(array[i] & 0xFF);
            if (hex.length() == 1)
            {
                stringBuilder.append("0");
            }
            stringBuilder.append(hex);
        }
        return stringBuilder.toString();
    }

 

来源:https://www./content-1-373801.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多