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
- Java干货之Socket自定义传输协议,可用于一般即时通讯
- JAVA中使用Socket实现自定义协议、无服务器即时通讯(类似飞秋)
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- Java网络编程之传输控制协议 socket
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- Java Socket实战之五:使用加密协议传输对象
- Java Socket实战之五 使用加密协议传输对象
- 即时通讯基础之socket
- Java socket 分析1--Socket说明与传输协议
- Java Socket实战之三 传输对象
- mac安装brew
- Java之代理模式
- jackson中JsonFormat格式化时间少8小时
- python中文件写入TXT
- failed to copy 'tcpdump' to '/data/local/tcpdump': Permission denied
- Java干货之Socket自定义传输协议,可用于一般即时通讯
- Anaconda安装tensorflow时遇到的那些坑
- SpringMvc解决跨域问题
- Java笔试:Java volatitle关键字
- com.baidu.disconf.core.common.utils.ZooUtils
- 告白气球
- 关于数据库的几个实用规则
- Android 6.0动态权限申请
- Memcached 及 Redis 架构分析和比较