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

原型

客户端 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> 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>();
    }

    /**
     * 提交文件
     * 
     * @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());
    }

    /**
     * 提交图文(添加文件)
     * 
     * @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 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 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 table = new Hashtable<>();
        ArrayList 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 {

    /**
     * 当数据到达
     * 
     * @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 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自定义传输协议源代码

你可能感兴趣的:(探究,原理,Java,新奇好玩)