Java Socket简例
Socket IO工具类:
package com.test.util; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class SocketIO{ public static DataInputStream getInput(Socket socket) throws IOException{ //接收缓存区大小,socket获取输入流之前设置 socket.setReceiveBufferSize(10); InputStream input = socket.getInputStream(); return new DataInputStream(input); } public static DataOutputStream getOutput(Socket socket) throws IOException{ //发送缓存区大小,socket获取输出流之前设置 socket.setSendBufferSize(10); OutputStream output = socket.getOutputStream(); return new DataOutputStream(output); } }
如果传输数据量较大,则应配置较大缓存区,以减少数据传输次数,提高数据传输效率
如果传输数据量较小并且比较频繁,则应配置较小缓存,以提高通信速度
Socket Client客户端:
package com.test.client; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import org.apache.log4j.Logger; import com.test.util.SocketIO; public class Client { static Logger logger = Logger.getLogger(Client.class); private int port = 10000; private String host = "127.0.0.1"; private Socket socket; public Client(){ try { socket = new Socket(); //关闭socket时,立即释放socket绑定端口以便端口重用,默认为false socket.setReuseAddress(true); //关闭传输缓存,默认为false socket.setTcpNoDelay(true); //如果输入流等待1000毫秒还未获得服务端发送数据,则提示超时,0为永不超时 socket.setSoTimeout(10000); //关闭socket时,底层socket不会直接关闭,会延迟一会,直到发送完所有数据 //等待10秒再关闭底层socket连接,0为立即关闭底层socket连接 socket.setSoLinger(true, 10); //设置性能参数,可设置任意整数,数值越大,相应的参数重要性越高(连接时间,延迟,带宽) socket.setPerformancePreferences(3, 2, 1); SocketAddress address = new InetSocketAddress(host, port); //socket创建超时时间为1000毫秒 socket.connect(address, 10000); logger.info("client ip:"+socket.getLocalAddress()); logger.info("client port:"+socket.getLocalPort()); logger.info("servetr ip:"+socket.getInetAddress()); logger.info("servetr port:"+socket.getPort()); } catch (IOException e) { e.printStackTrace(); logger.error("Cilent socket establish failed!"); } logger.info("Client socket establish success!"); } public void request(){ try{ DataOutputStream output = SocketIO.getOutput(socket); DataInputStream input = SocketIO.getInput(socket); String question = "your name?"; byte[] bytes = question.getBytes("utf-8"); int len = bytes.length; output.writeInt(len); output.write(bytes); len = input.readInt(); bytes = new byte[len]; input.read(bytes); logger.info("server answer:"+new String(bytes,"utf-8")); }catch(Exception e){ e.printStackTrace(); logger.error("client request error"); }finally{ if(null != socket){ try{ socket.close(); }catch(Exception e){ e.printStackTrace(); logger.error("socket close error"); } } } } public static void main(String[] args){ Client client = new Client(); client.request(); } }
Socket Server服务端:
package com.test.server; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import org.apache.log4j.Logger; import com.test.util.SocketIO; public class Server { static Logger logger = Logger.getLogger(Server.class); private int queueSize = 10; private int port = 10000; private ServerSocket serverSocket; public Server(){ try{ serverSocket = new ServerSocket(); //关闭serverSocket时,立即释放serverSocket绑定端口以便端口重用,默认为false serverSocket.setReuseAddress(true); //accept等待连接超时时间为1000毫秒,默认为0,永不超时 //serverSocket.setSoTimeout(10000); //为所有accept方法返回的socket对象设置接收缓存区大小,单位为字节,默认值和操作系统有关 serverSocket.setReceiveBufferSize(128*1024); //设置性能参数,可设置任意整数,数值越大,相应的参数重要性越高(连接时间,延迟,带宽) serverSocket.setPerformancePreferences(3, 2, 1); //服务端绑定至端口,10为服务端连接请求队列长度 serverSocket.bind(new InetSocketAddress(port), queueSize); }catch(Exception e){ e.printStackTrace(); logger.error("Server establish error!"); } logger.info("Server start up!"); } public void service(){ while(true){ Socket socket = null; try{ //从连接请求队列中取出一个客户连接请求,创建与客户连接的socket对象 //如果队列中没有请求,accept方法就会一直等待 socket = serverSocket.accept(); DataOutputStream output = SocketIO.getOutput(socket); DataInputStream input = SocketIO.getInput(socket); int len = input.readInt(); byte[] bytes = new byte[len]; input.read(bytes); String request = new String(bytes, "utf-8"); logger.info("client request:"+request); String answer = "not supported"; if(request.equals("your name?")){ answer = "server"; } bytes = answer.getBytes("utf-8"); len = bytes.length; output.writeInt(len); output.write(bytes); }catch(Exception e){ e.printStackTrace(); logger.error("Server run exception!"); } } } public static void main(String[] args) { Server server = new Server(); server.service(); } }
log4j.properties日志设置:
log4j.rootLogger=info,logOutput #log console out put log4j.appender.logOutput=org.apache.log4j.ConsoleAppender log4j.appender.logOutput.layout=org.apache.log4j.PatternLayout log4j.appender.logOutput.layout.ConversionPattern=%p%d{[yy-MM-dd HH:mm:ss]}[%c] -> %m%n
Client端日志:
INFO[13-10-10 10:04:23][com.test.client.Client] -> client ip:/127.0.0.1 INFO[13-10-10 10:04:23][com.test.client.Client] -> client port:52362 INFO[13-10-10 10:04:23][com.test.client.Client] -> servetr ip:/127.0.0.1 INFO[13-10-10 10:04:23][com.test.client.Client] -> servetr port:10000 INFO[13-10-10 10:04:23][com.test.client.Client] -> Client socket establish success! INFO[13-10-10 10:04:23][com.test.client.Client] -> server answer:server
Server端日志:
INFO[13-10-10 10:04:19][com.test.server.Server] -> Server start up! INFO[13-10-10 10:04:23][com.test.server.Server] -> client request:your name?
PS:
这里要特别说明一下DataInputStream这个类的readShort方法:
public final short readShort() throws IOException { int ch1 = in.read(); int ch2 = in.read(); if ((ch1 | ch2) < 0) throw new EOFException(); return (short)((ch1 << 8) + (ch2 << 0)); }
可以看到是先读高位,再读低位
再来看下DataOutputStream这个类的writeShort方法:
public final void writeShort(int v) throws IOException { out.write((v >>> 8) & 0xFF); out.write((v >>> 0) & 0xFF); incCount(2); }
可以看到是先写高位,再写低位
如果传输Short类型数据(其它类型数据相同)时,要求先传低位,再传高位,则不能使用自带的方法
将数据转为低位在前高位在后的字节数组,然后传输整个数组即可
public void write(byte b[]) throws IOException { write(b, 0, b.length); }
public void write(byte b[], int off, int len) throws IOException { if ((off | len | (b.length - (len + off)) | (off + len)) < 0) throw new IndexOutOfBoundsException(); for (int i = 0 ; i < len ; i++) { write(b[off + i]); } }