常见问题集合
http://blog.csdn.net/allanking666/article/details/5020864
使用传统套接字,进行收发数据包的小实验
客户端代码
int port = 7777; int kb = 1024; int load = 10; Socket socket = new Socket("localhost", port); OutputStream outputStream = socket.getOutputStream(); // 12 byte String msgUnit = "m"; System.out.println(msgUnit.getBytes().length); StringBuffer msg = new StringBuffer(); for (int i = 0; i < load * kb; i++) { msg.append(msgUnit); } System.out.println(msg.toString().getBytes().length / kb + "kb"); long start = System.currentTimeMillis(); DataOutputStream dataOutputStream = new DataOutputStream(outputStream); dataOutputStream.writeInt(load); ObjectOutput objectOutput = new ObjectOutputStream(outputStream); List<String> list = new ArrayList<String>(); list.add("hello world"); objectOutput.writeObject(list); outputStream.write(msg.toString().getBytes()); System.out.println(System.currentTimeMillis() - start); outputStream.flush(); while (true) { }
(在本机C-S环境调用socket.getOutputStream().flush(),几乎没看到任何效果,是因为SocketOutputStream没有对flush方法进行实现,jvm没有对此的缓冲区。flush和Nagle's 算法无关)
使用BufferedOutputStream作为输出流则能看到效果,默认缓冲区是8kb。当write的数据不足8kb时,则需要调用flush,才会发出数据包(BufferedOutputStream通过使用buffer可以用于减少jvm和系统内核的交互次数,提高性能和吞吐量)。代码如下
BufferedOutputStream bos = new BufferedOutputStream(outputStream); bos.write(msgByte);
服务端代码
int port = 7777; int kb = 1024; ServerSocket serverSocket = new ServerSocket(port); while (true) { Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); DataInputStream dataInputStream = new DataInputStream(inputStream); byte[] b = new byte[kb]; int load = dataInputStream.readInt(); ObjectInput objectInput = new ObjectInputStream(inputStream); List<String> list = (List<String>) objectInput.readObject(); System.out.println(list.get(0)); for (int i = 0; i < load; i++) { inputStream.read(b); System.out.println(new String(b)); } }
当客户端 dataOutputStream.writeInt(load),数据包马上发出;服务端int load = dataInputStream.readInt()读取到数据。所以当多线程公用一个连接收发包,并且一个完整请求由多次write触发的时候,要防止串号。
如果要先把object转为byte,再用OutputStream.write(byte[] b),可以使用这种方式
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutput objectOutput = new ObjectOutputStream(byteArrayOutputStream); List<String> list = new ArrayList<String>(); list.add("hello world"); objectOutput.writeObject(list); outputStream.write(byteArrayOutputStream.toByteArray());
也就是说byte和对象的输入输出流转化可以组合使用ByteArray*putStream和Object*putStream。数值类型和byte的转换同理可得。(http://www.360doc.com/content/07/0914/15/11586_743633.shtml)
byte版本的客户端和服务端代码,可以解决一个完整的请求通过一次write发送,避免多线程串号。
客户端
int port = 7777; int kb = 1024; int load = 10; Socket socket = new Socket("localhost", port); OutputStream outputStream = socket.getOutputStream(); // 12 byte String msgUnit = "m"; System.out.println(msgUnit.getBytes().length); StringBuffer msg = new StringBuffer(); for (int i = 0; i < load * kb; i++) { msg.append(msgUnit); } System.out.println(msg.toString().getBytes().length / kb + "kb"); byte[] msgByte = msg.toString().getBytes(); long start = System.currentTimeMillis(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); // DataOutputStream dataOutputStream = new // DataOutputStream(outputStream); dataOutputStream.writeInt(load); byte[] intByte = byteArrayOutputStream.toByteArray(); byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutput objectOutput = new ObjectOutputStream(byteArrayOutputStream); List<String> list = new ArrayList<String>(); list.add("hello world"); objectOutput.writeObject(list); byte[] objectByte = byteArrayOutputStream.toByteArray(); byte[] totalByte = new byte[intByte.length + objectByte.length + msgByte.length]; System.arraycopy(intByte, 0, totalByte, 0, intByte.length); System.arraycopy(objectByte, 0, totalByte, intByte.length, objectByte.length); System.arraycopy(msgByte, 0, totalByte, intByte.length + objectByte.length, msgByte.length); // outputStream.write(objectByte); outputStream.write(totalByte); System.out.println(System.currentTimeMillis() - start); outputStream.flush(); while (true) { }
服务端保持不变
int port = 7777; int kb = 1024; ServerSocket serverSocket = new ServerSocket(port); while (true) { Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); DataInputStream dataInputStream = new DataInputStream(inputStream); byte[] b = new byte[kb]; int load = dataInputStream.readInt(); ObjectInput objectInput = new ObjectInputStream(inputStream); List<String> list = (List<String>) objectInput.readObject(); System.out.println(list.get(0)); for (int i = 0; i < load; i++) { inputStream.read(b); System.out.println(new String(b)); } }