由于项目上的 http 请求量较大,项目上性能跟不上。于是考虑把 短连接的 http 换成 长连接的tcp 形式 试试效果。
先 研究了一下 长连接方式。就是要用到 socket 方面的知识。
package com.bkc.bpmp.common.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; /** * 搭建服务器端 a)、创建ServerSocket对象绑定监听端口。 b)、通过accept()方法监听客户端的请求。 c)、建立连接后,通过输入输出流读取客户端发送的请求信息。 d)、通过输出流向客户端发送请求信息。 e)、关闭相关资源。 * @author ppnie * */ public class SocketService { // 搭建服务器端 public static void main(String[] args) throws IOException { SocketService socketService = new SocketService(); // 1、a)创建一个服务器端Socket,即SocketService socketService.oneServer(); } public void oneServer() { try { ServerSocket server = null; try { server = new ServerSocket(5209); // b)指定绑定的端口,并监听此端口。 System.out.println("服务器启动成功"); // 创建一个ServerSocket在端口5209监听客户请求 } catch (Exception e) { System.out.println("没有启动监听:" + e); // 出错,打印出错信息 } Socket socket = null; try { socket = server.accept(); // 2、调用accept()方法开始监听,等待客户端的连接 // 使用accept()阻塞等待客户请求,有客户 // 请求到来则产生一个Socket对象,并继续执行 } catch (Exception e) { System.out.println("Error." + e); // 出错,打印出错信息 } // 3、获取输入流,并读取客户端信息 String line; BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket对象得到输入流,并构造相应的BufferedReader对象 PrintWriter writer = new PrintWriter(socket.getOutputStream()); // 由Socket对象得到输出流,并构造PrintWriter对象 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系统标准输入设备构造BufferedReader对象 System.out.println("Client:" + in.readLine()); // 在标准输出上打印从客户端读入的字符串 line = br.readLine(); // 从标准输入读入一字符串 // 4、获取输出流,响应客户端的请求 while (!line.equals("end")) { // 如果该字符串为 "bye",则停止循环 writer.println(line); // 向客户端输出该字符串 writer.flush(); // 刷新输出流,使Client马上收到该字符串 System.out.println("Server:" + line); // 在系统标准输出上打印读入的字符串 System.out.println("Client:" + in.readLine()); // 从Client读入一字符串,并打印到标准输出上 line = br.readLine(); // 从系统标准输入读入一字符串 } // 继续循环 // 5、关闭资源 writer.close(); // 关闭Socket输出流 in.close(); // 关闭Socket输入流 socket.close(); // 关闭Socket server.close(); // 关闭ServerSocket } catch (Exception e) {// 出错,打印出错信息 System.out.println("Error." + e); } } } package com.bkc.bpmp.common.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class SocketClient { // 搭建客户端 public static void main(String[] args) throws IOException { try { // 1、创建客户端Socket,指定服务器地址和端口 // Socket socket=new Socket("127.0.0.1",5200); Socket socket = new Socket("192.168.1.99", 5209); System.out.println("客户端启动成功"); // 2、获取输出流,向服务器端发送信息 // 向本机的52000端口发出客户请求 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系统标准输入设备构造BufferedReader对象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket对象得到输出流,并构造PrintWriter对象 // 3、获取输入流,并读取服务器端的响应信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket对象得到输入流,并构造相应的BufferedReader对象 String readline; readline = br.readLine(); // 从系统标准输入读入一字符串 while (!readline.equals("end")) { // 若从标准输入读入的字符串为 "end"则停止循环 write.println(readline); // 将从系统标准输入读入的字符串输出到Server write.flush(); // 刷新输出流,使Server马上收到该字符串 System.out.println("Client:" + readline); // 在系统标准输出上打印读入的字符串 System.out.println("Server:" + in.readLine()); // 从Server读入一字符串,并打印到标准输出上 readline = br.readLine(); // 从系统标准输入读入一字符串 } // 继续循环 // 4、关闭资源 write.close(); // 关闭Socket输出流 in.close(); // 关闭Socket输入流 socket.close(); // 关闭Socket } catch (Exception e) { System.out.println("can not listen to:" + e);// 出错,打印出错信息 } } }
这是一个简单的 用java 实现 socket 客户端与服务端的 代码。
但是这样的例子,并不能实际运用与项目之中。在实际项目中需要考虑到 套接字的连接什么时候关闭,流什么时候关闭,参数的传入与信息的响应都需要得到结果。
若是这里使用的方法同 http 的话,应该是 一个请求一个对应的响应结果,若是长连接,应该如何把多线程与长连接 结合起来呢?
现在的项目是 使用C++ 服务端 和 java 客户端 来使用 socket 进行通信。
C++ 与 Java 之间的通信还涉及到了一个 网络字节码 不一致的问题。以及 还有一个 自定义协议 的问题
假设 自定义协议 为
java 客户端代码(至于这里的BytePtr ,就是 网络字节码 的转码)
public class BytePtr { public static byte[] toLH(short n) { byte[] b = new byte[2]; b[0] = (byte) (n & 0xff); b[1] = (byte) (n >> 8 & 0xff); return b; } public static byte [] toLH( int n) { byte [] b = new byte [ 4 ]; b[0 ] = ( byte ) (n & 0xff ); b[1 ] = ( byte ) (n >> 8 & 0xff ); b[2 ] = ( byte ) (n >> 16 & 0xff ); b[3 ] = ( byte ) (n >> 24 & 0xff ); return b; } public static byte[] addBytes(byte[] data1, byte[] data2) { byte[] data3 = new byte[data1.length + data2.length]; System.arraycopy(data1, 0, data3, 0, data1.length); System.arraycopy(data2, 0, data3, data1.length, data2.length); return data3; } } import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class ChatClient { public static void main(String[] args) { try { Socket client = new Socket("192.168.1.108", 10008); OutputStream out = client.getOutputStream(); DataOutputStream outs = new DataOutputStream(out); Scanner scaner = new Scanner(System.in); genProtocol(outs, scaner.next()); parseProtocol(client); outs.close(); out.close(); client.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 构造协议 * * @param out * @param msg * @throws IOException */ private static void genProtocol(DataOutputStream out, String msg) throws IOException { short type = 10001; // 消息类型 byte[] bytes = msg.getBytes(); // 消息内容 int totalLen = bytes.length; // 消息长度 out.write((BytePtr.addBytes(BytePtr.addBytes(BytePtr.toLH(type), BytePtr.toLH(totalLen)), bytes))); // 写入消息内容 out.flush(); } private static void parseProtocol(Socket client) throws IOException { InputStream is = client.getInputStream(); DataInputStream dis = new DataInputStream(is); // 读取Java标准数据类型的输入流 // 协议解析 int totalLen = dis.readInt(); // 读取消息长度 byte[] data = new byte[totalLen]; // 定义存放消息内容的字节数组 int len = is.read(data); String text = new String(data, 0, len); System.out.println("发来的内容是:" + text); is.close(); dis.close(); } }
哦,这里还提到 一个工具 Wireshark,用来抓取包,来查看一下网络字节码到底传送的是一些什么
哦,还有 提到的 netty 技术,至于怎么用,还是先看看再说。
至于 有一些电子书之类的,可以 到脚本之家 去下载。
最最重要的一点,下载的电子书、视频、源码 之类的,一定要看啊。