Java干货之Socket自定义传输协议,可用于一般即时通讯

来源:互联网 发布:oracle for linux 编辑:程序博客网 时间:2024/05/09 10:39

原型

客户端 Client

package me.mxzf;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.net.Socket;/** *  * @Title: Client * @Dscription: 客户端原型 * @author Deleter * @date 2017年3月12日 下午1:32:13 * @version 1.0 */public class Client {    public static final int STREAM_TEXT = 1;// 文本信息    public static final int STREAM_FILE = 2;// 一般文件    public static final int STREAM_IMG = 3;// 图片文件    public static final int STREAM_VOICE = 4;// 音频文件    public static void main(String[] args) {        Socket socket;        BufferedOutputStream bufferedOutput;        BufferedInputStream bufferedInput;        DataOutputStream outputStream;        DataInputStream inputStream;        String responseMsg; // 响应内容        StringBuilder content = new StringBuilder();// 测试内容        try {            socket = new Socket("localhost", 1234);// 连接地址localhost,端口1234            bufferedOutput = new BufferedOutputStream(socket.getOutputStream());// 包装流            bufferedInput = new BufferedInputStream(socket.getInputStream());            outputStream = new DataOutputStream(bufferedOutput);            inputStream = new DataInputStream(bufferedInput);            /*             * 发送文本信息             */            for (int i = 0; i < 100; i++) {                content.append("测试文本");// 追加文本x100            }            Thread.sleep(5000);            responseMsg = writeContent(content.toString(), inputStream,                    outputStream);            System.out.println(responseMsg);            /*             * 发送文件             */            responseMsg = writeFile(new File("C:/DB.zip"), STREAM_FILE,                    inputStream, outputStream);            System.out.println(responseMsg);            Thread.sleep(5000);            /*             * 发送图片             */            responseMsg = writeFile(new File("C:/DB.jpg"), STREAM_IMG,                    inputStream, outputStream);            System.out.println(responseMsg);            Thread.sleep(5000);            /*             * 发送音频             */            responseMsg = writeFile(new File("C:/DB.wma"), STREAM_VOICE,                    inputStream, outputStream);            System.out.println(responseMsg);            socket.close();// 关闭套接字        } catch (IOException e) {            e.printStackTrace();// IO异常        } catch (InterruptedException e) {            e.printStackTrace();// 线程中断异常        }    }    /*     * 文本信息传输协议     */    public static String writeContent(String content,            DataInputStream inputStream, DataOutputStream outputStream)            throws IOException {        outputStream.writeInt(STREAM_TEXT);// 写类型        outputStream.writeInt(content.length());// 写长度        outputStream.writeUTF(content.toString());// 写数据        outputStream.flush();        return inputStream.readUTF();    }    /*     * 文件传输协议     */    public static String writeFile(File file, int dataType,            DataInputStream inputStream, DataOutputStream outputStream)            throws IOException {        int len;        byte[] buff = new byte[2048];        FileInputStream fis = new FileInputStream(file);// 读文件        outputStream.writeInt(dataType);// 写类型        outputStream.writeLong(file.length());// 写总长度        outputStream.writeUTF(file.getName());// 写文件名        while ((len = fis.read(buff)) != -1) { // 循环写            outputStream.writeInt(len);// 数据长度            outputStream.write(buff, 0, len);// 数据        }        fis.close();// 关闭文件流        outputStream.flush();        String responseMsg = inputStream.readUTF();        return responseMsg;    }}

服务端 Server

package me.mxzf;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;/** *  * @Title: Server * @Dscription: 服务器原型 * @author Deleter * @date 2017年3月12日 下午1:32:11 * @version 1.0 */public class Server {    public static void main(String[] args) {        Socket socket = null;        ServerSocket serverSocket = null;        BufferedOutputStream bufferedOutput;        BufferedInputStream bufferedInput;        DataOutputStream outputStream;        DataInputStream inputStream;        try {            serverSocket = new ServerSocket(1234);            socket = serverSocket.accept();            bufferedOutput = new BufferedOutputStream(socket.getOutputStream());            bufferedInput = new BufferedInputStream(socket.getInputStream());            outputStream = new DataOutputStream(bufferedOutput);            inputStream = new DataInputStream(bufferedInput);            int dataType;            while (true) {                dataType = inputStream.readInt();// 读类型                switch (dataType) {                case Client.STREAM_TEXT:                    System.out                            .println(receiveContent(inputStream, outputStream));                    break;                case Client.STREAM_FILE:                    receiveFile("d:/", Client.STREAM_FILE, inputStream,                            outputStream);                    break;                case Client.STREAM_IMG:                    receiveFile("d:/", Client.STREAM_IMG, inputStream,                            outputStream);                    break;                case Client.STREAM_VOICE:                    receiveFile("d:/", Client.STREAM_VOICE, inputStream,                            outputStream);                    break;                }            }        } catch (IOException e) {            // 忽略        }    }    /*     * 文本信息传输协议     */    public static String receiveContent(DataInputStream inputStream,            DataOutputStream outputStream) throws IOException {        int dataLength = inputStream.readInt();// 读长度        if (dataLength == 0)            return "txt_err";        String content = inputStream.readUTF();        outputStream.writeUTF("txt_ok");        outputStream.flush();        return content;    }    /*     * 文件传输协议     */    public static void receiveFile(String dirPath, int dataType,            DataInputStream inputStream, DataOutputStream outputStream)            throws IOException {        String responseMsg = "";        long totalLength = 0;        int getLength = 0;        byte[] buff = new byte[2048];        switch (dataType) {        case Client.STREAM_FILE:            responseMsg = "file_ok";            break;        case Client.STREAM_IMG:            responseMsg = "img_ok";            break;        case Client.STREAM_VOICE:            responseMsg = "voice_ok";            break;        }        long dataLength = inputStream.readLong();// 读总长度        String fileName = inputStream.readUTF();// 读文件名        FileOutputStream fos = new FileOutputStream(new File(dirPath, fileName));// 读文件        while (true) {            if (totalLength == dataLength) {                break;            }            getLength = inputStream.readInt();            totalLength += getLength;            inputStream.read(buff, 0, getLength);            fos.write(buff, 0, getLength);        }        fos.close();// 关闭文件流        outputStream.writeUTF(responseMsg);        outputStream.flush();    }}

重构、多线程、代理

客户端 MiniClient

package me.mxzf.rebuild;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.net.Socket;import java.net.UnknownHostException;import java.util.ArrayList;import java.util.Hashtable;/** *  * @Title: MiniClient * @Dscription: 客户端 * @author Deleter * @date 2017年3月15日 下午12:52:58 * @version 1.0 */public class MiniClient {    public static final int STREAM_TEXT = 1;    public static final int STREAM_FILE = 2;    public static final int STREAM_IMG = 3;    public static final int STREAM_VOICE = 4;    public static final int STREAM_ASYNC = 5;    private String hostName;    private Integer port;    private Socket socket;    private DataOutputStream outputStream;    private DataInputStream inputStream;    private String title;    private Hashtable<String, ArrayList<File>> asyncList;    /**     * 构造函数     *      * @param hostName     *            服务器地址     * @param port     *            端口     */    public MiniClient(String hostName, Integer port) {        this.hostName = hostName;        this.port = port;    }    /**     * 初始化     *      * @throws UnknownHostException     * @throws IOException     */    public void init() throws UnknownHostException, IOException {        this.socket = new Socket(this.hostName, this.port);        this.outputStream = new DataOutputStream(new BufferedOutputStream(                this.socket.getOutputStream()));        this.inputStream = new DataInputStream(new BufferedInputStream(                this.socket.getInputStream()));        this.asyncList = new Hashtable<String, ArrayList<File>>();    }    /**     * 提交文件     *      * @param dataType     *            文件类型     * @param file     *            文件     * @return 响应内容     * @throws IOException     */    public String postFile(int dataType, File file) throws IOException {        int len;        byte[] buff = new byte[2048];        FileInputStream fis = new FileInputStream(file);// 读文件        this.outputStream.writeInt(dataType);// 写类型        this.outputStream.writeLong(file.length());// 写总长度        this.outputStream.writeUTF(file.getName());// 写文件名        while ((len = fis.read(buff)) != -1) { // 循环写            this.outputStream.writeInt(len);// 数据长度            this.outputStream.write(buff, 0, len);// 数据        }        fis.close();// 关闭文件流        this.outputStream.flush();        return this.inputStream.readUTF();    }    /**     * 提交文本     *      * @param content     *            文本内容     * @return 响应内容     * @throws IOException     */    public String postText(String content) throws IOException {        this.outputStream.writeInt(STREAM_TEXT);// 写类型        this.outputStream.writeInt(content.length());// 写长度        this.outputStream.writeUTF(content.toString());// 写数据        this.outputStream.flush();        return this.inputStream.readUTF();    }    /**     * 提交图文(设置标题)     *      * @param title     *            标题     */    public void setTitle(String title) {        this.title = title;        this.asyncList.put(title, new ArrayList<File>());    }    /**     * 提交图文(添加文件)     *      * @param file     *            文件     */    public void addFile(File file) {        if (this.asyncList.get(this.title) != null)            this.asyncList.get(this.title).add(file);    }    /**     * 提交图文     *      * @return String 响应信息     * @throws IOException     */    public String postAsync() throws IOException {        int len;        int size;        byte[] buff = new byte[2048];        FileInputStream fis;        ArrayList<File> files = this.asyncList.get(this.title);        this.outputStream.writeInt(STREAM_ASYNC);// 写类型        this.outputStream.writeUTF(this.title);// 写标题        size = asyncList.get(this.title).size();        this.outputStream.writeInt(size);// 写文件数量        for (int i = 0; i < size; i++) {            fis = new FileInputStream(files.get(i));// 读文件            this.outputStream.writeLong(files.get(i).length());// 写总长度            this.outputStream.writeUTF(files.get(i).getName());// 写文件名            while ((len = fis.read(buff)) != -1) { // 循环写                this.outputStream.writeInt(len);// 数据长度                this.outputStream.write(buff, 0, len);// 数据            }            fis.close();// 关闭文件流            this.outputStream.flush();        }        // 清理内存        this.asyncList.clear();        return this.inputStream.readUTF();    }    /**     * 关闭套接字     *      * @throws IOException     */    public void close() throws IOException {        this.socket.close();    }}

服务端 MiniServer

package me.mxzf.rebuild;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import me.mxzf.rebuild.handler.impl.AsyncHandler;import me.mxzf.rebuild.handler.impl.FileHandler;import me.mxzf.rebuild.handler.impl.TextHandler;/** *  * @Title: MiniServer * @Dscription: 服务器 * @author Deleter * @date 2017年3月15日 下午12:53:07 * @version 1.0 */public class MiniServer {    private Integer port;    private Socket socket;    private ServerSocket serverSocket;    private ThreadMiniServer threadMiniServer;    public MiniServer(Integer port) {        this.port = port;    }    public void init(String dirPath) throws IOException {        serverSocket = new ServerSocket(this.port);        while (true) {            socket = serverSocket.accept();            threadMiniServer = new ThreadMiniServer(socket, dirPath);            threadMiniServer.setTextHandler(new TextHandler());            threadMiniServer.setFileHandler(new FileHandler());            threadMiniServer.setAsyncHandler(new AsyncHandler());            threadMiniServer.start();        }    }}

服务线程 ThreadMiniServer

package me.mxzf.rebuild;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.net.Socket;import java.util.ArrayList;import java.util.Hashtable;import me.mxzf.Client;import me.mxzf.rebuild.handler.impl.AsyncHandler;import me.mxzf.rebuild.handler.impl.FileHandler;import me.mxzf.rebuild.handler.impl.TextHandler;/** *  * @Title: ThreadMiniServer * @Dscription: 服务线程 * @author Deleter * @date 2017年3月15日 下午2:37:20 * @version 1.0 */public class ThreadMiniServer extends Thread {    private Socket socket;    private DataOutputStream outputStream;    private DataInputStream inputStream;    private String dirPath;    private int dataType;    private TextHandler textHandler;    private FileHandler fileHandler;    private AsyncHandler asyncHandler;    public ThreadMiniServer(Socket socket, String dirPath) {        this.socket = socket;        this.dirPath = dirPath;    }    public TextHandler getTextHandler() {        return textHandler;    }    public void setTextHandler(TextHandler textHandler) {        this.textHandler = textHandler;    }    public FileHandler getFileHandler() {        return fileHandler;    }    public void setFileHandler(FileHandler fileHandler) {        this.fileHandler = fileHandler;    }    public AsyncHandler getAsyncHandler() {        return asyncHandler;    }    public void setAsyncHandler(AsyncHandler asyncHandler) {        this.asyncHandler = asyncHandler;    }    @Override    public void run() {        try {            outputStream = new DataOutputStream(new BufferedOutputStream(                    socket.getOutputStream()));            inputStream = new DataInputStream(new BufferedInputStream(                    socket.getInputStream()));            while (true) {                dataType = inputStream.readInt();// 读类型                switch (dataType) {                case MiniClient.STREAM_TEXT:                    textHandler.onMessage(receiveContent(this.inputStream,                            this.outputStream));                    break;                case MiniClient.STREAM_FILE:                    fileHandler.onMessage(receiveFile(this.dirPath,                            Client.STREAM_FILE, this.inputStream,                            this.outputStream));                    break;                case MiniClient.STREAM_IMG:                    fileHandler.onMessage(receiveFile(this.dirPath,                            Client.STREAM_IMG, this.inputStream,                            this.outputStream));                    break;                case MiniClient.STREAM_VOICE:                    fileHandler.onMessage(receiveFile(this.dirPath,                            Client.STREAM_VOICE, this.inputStream,                            this.outputStream));                    break;                case MiniClient.STREAM_ASYNC:                    asyncHandler.onMessage(receiveAsync(this.dirPath,                            this.inputStream, this.outputStream));                    break;                }            }        } catch (IOException e) {            // 忽略EOF        }    }    /*     * 文本信息传输协议     */    private String receiveContent(DataInputStream inputStream,            DataOutputStream outputStream) throws IOException {        int dataLength = inputStream.readInt();// 读长度        if (dataLength == 0)            return "text_err";        String content = inputStream.readUTF();        outputStream.writeUTF("text_ok");        outputStream.flush();        return content;    }    /*     * 文件传输协议     * @param dirPath 目录路径     * @param dataType 数据类型     */    private String receiveFile(String dirPath, int dataType,            DataInputStream inputStream, DataOutputStream outputStream)            throws IOException {        String responseMsg = "";        long totalLength = 0;        int getLength = 0;        byte[] buff = new byte[2048];        switch (dataType) {        case Client.STREAM_FILE:            responseMsg = "file_ok";            break;        case Client.STREAM_IMG:            responseMsg = "img_ok";            break;        case Client.STREAM_VOICE:            responseMsg = "voice_ok";            break;        }        long dataLength = inputStream.readLong();// 读总长度        String fileName = inputStream.readUTF();// 读文件名        File file = new File(dirPath, fileName);        FileOutputStream fos = new FileOutputStream(file);// 写文件        while (true) {            if (totalLength == dataLength) {                break;            }            getLength = inputStream.readInt();            totalLength += getLength;            inputStream.read(buff, 0, getLength);            fos.write(buff, 0, getLength);        }        fos.close();// 关闭文件流        outputStream.writeUTF(responseMsg);        outputStream.flush();        return file.getAbsolutePath();    }    /*     * 混合传输协议     * @param dirPath 目录路径     */    private Hashtable<String, Object> receiveAsync(String dirPath,            DataInputStream inputStream, DataOutputStream outputStream)            throws IOException {        int size;        int index = 0;        int getLength;        long dataLength;        long totalLength;        String title;        String fileName;        File file;        FileOutputStream fos;        byte[] buff = new byte[2048];        StringBuilder sb = new StringBuilder();        Hashtable<String, Object> table = new Hashtable<>();        ArrayList<String> filePaths = new ArrayList<>();        title = inputStream.readUTF();// 读标题        table.put("title", title);        size = inputStream.readInt();// 读取图片数量        table.put("size", size);        while (index++ < size) {            getLength = 0;            dataLength = 0;            totalLength = 0;            dataLength = inputStream.readLong();// 读总长            fileName = inputStream.readUTF();// 读文件名            // 写文件            file = new File(dirPath, System.currentTimeMillis() + fileName);            fos = new FileOutputStream(file);            while (true) {                if (totalLength == dataLength) {                    break;                }                getLength = inputStream.readInt();                totalLength += getLength;                inputStream.read(buff, 0, getLength);                fos.write(buff, 0, getLength);            }            fos.close();// 关闭文件流            sb.append(index);            sb.append(":ok,");            filePaths.add(file.getAbsolutePath());// 添加文件路径        }        table.put("paths", filePaths);        outputStream.writeUTF(sb.substring(0, sb.length() - 1));        outputStream.flush();        return table;    }}

数据处理器

一般接口 BaseHandler

package me.mxzf.rebuild.handler;import java.io.IOException;/** *  * @Title: BaseHandler * @Dscription: 基本处理器 * @author Deleter * @date 2017年3月15日 下午2:06:52 * @version 1.0 */public interface BaseHandler<T> {    /**     * 当数据到达     *      * @param t     *            数据     * @throws IOException     */    public void onMessage(T t) throws IOException;}

字符串处理器 TextHandler

package me.mxzf.rebuild.handler.impl;import java.io.IOException;import me.mxzf.rebuild.handler.BaseHandler;public class TextHandler implements BaseHandler<String> {    /**     * @param t     *            文本内容     */    @Override    public void onMessage(String t) throws IOException {        // 处理数据    }}

文件处理器 FileHandler

package me.mxzf.rebuild.handler.impl;import java.io.IOException;import me.mxzf.rebuild.handler.BaseHandler;public class FileHandler implements BaseHandler<String> {    /**     * @param t     *            文件所在的路径     */    @Override    public void onMessage(String t) throws IOException {        // 处理数据    }}

图文混传处理器 AsyncHandler

package me.mxzf.rebuild.handler.impl;import java.io.IOException;import java.util.Hashtable;import me.mxzf.rebuild.handler.BaseHandler;/** *  * @Title: AsyncHandler * @Dscription: 混合处理器 * @author Deleter * @date 2017年3月15日 下午2:17:17 * @version 1.0 */public class AsyncHandler implements BaseHandler<Hashtable<String, Object>> {    /**     * @param title     *            标题     * @param size     *            图片数量     * @param paths     *            文件路径     */    @Override    public void onMessage(Hashtable<String, Object> table) throws IOException {        // 处理数据    }}

测试、样例

客户端

package me.mxzf.rebuild.test;import java.io.File;import java.io.IOException;import me.mxzf.rebuild.MiniClient;public class ClientTest {    public static void main(String[] args) {        try {            Thread.sleep(3000);            MiniClient client = new MiniClient("localhost", 1234);            client.init();            client.setTitle("浙大科技园");            client.addFile(new File("C:/DB.zip"));            client.addFile(new File("C:/DB.wma"));            client.addFile(new File("C:/DB.jpg"));            String result = client.postAsync();            System.out.println(result);        } catch (IOException e) {            e.printStackTrace();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

服务端

package me.mxzf.rebuild.test;import java.io.IOException;import me.mxzf.rebuild.MiniServer;public class ServerTest {    public static void main(String[] args) {        try {            MiniServer miniServer = new MiniServer(1234);            miniServer.init("D:/");        } catch (IOException e) {            e.printStackTrace();        }    }}

就这么多了,没有使用框架,bug暂时没有发现,如果有测试出有什么问题的,请给我留言,谢谢。


源代码:Socket自定义传输协议源代码

0 0
原创粉丝点击