Socket 网络模型结构
不同网络间的主机要进行消息交互时,这时我们就需要用到socket了,socket基于TCP/IP协议。
图片来自《TPC/IP协议详解卷一》
上图是TCP/IP四层网络模型,而socket所处位置在于
Socket主要是对TCP/IP基本网络结构的抽象整合,socket整体对运输层、网络层和链路层进行封装,使得基于Socket开发不必关心下层实现,并且开发者可以基于自己需求,自由选择网络传输协议,如:HTTP、RPC、SMTP等。
DEMO
DemoSocket
public class DemoSocket { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 8080); InputStream inputStream = socket.getInputStream(); //输出IO流 OutputStream outputStream = socket.getOutputStream(); PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream), true); pw.println("Hello Tomcat!"); StringBuffer requestResult = new StringBuffer(); byte[] bytes = new byte[1024]; while(inputStream.read(bytes) != -1) { String s = new String(bytes); System.out.println(s); requestResult.append(s); } System.out.println(requestResult); Thread.currentThread().sleep(50); socket.close(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } }}
DemoServer
private final static String REQUEST_SUCCESS = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "请求成功" ; public static void main(String[] args) { try { //创建SocketServer ServerSocket serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("localhost")); boolean stop = false; while(!stop) { //获取Socket Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); //读取请求数据 StringBuffer requestInfo = new StringBuffer(); byte[] bytes = new byte[1024]; if(inputStream.read(bytes) != -1) { String s = new String(bytes); System.out.println(s); requestInfo.append(s); } System.out.println("Request Info:" + requestInfo); //输出结果数据 outputStream.write(REQUEST_SUCCESS.getBytes()); socket.close(); } } catch (IOException e) { e.printStackTrace(); }
加了注释,理解不难
Demo测试
先运行DemoServer,再运行DemoSocket即可
DemoServer运行结果 DemoSocket运行结果页面测试
分析
基于Socket模型,我们已经简单实现了一个 服务,但还称不上服务容器。
ServerSocket主要是对端口进行监听,并获取对应Socket连接,以下是Socket主要使用到的方法public ServerSocket(int port, //端口0到65535 int backlog, //等待队列大小 @Nullable InetAddress bindAddr) //绑定地址public void bind(SocketAddress endpoint, int backlog) //绑定地址,InetAddress是SocketAddress子类public Socket accept() //监听并获Socketpublic void close() //关闭ServerSocket
Socket主要是承担网络连接工作,一下是Socket的主要方法
public Socket(String host, int port) //创建Socket连接public Socket(Proxy proxy) //基于代理模式的Socket连接,Dubbo中的代理模式基于这种方式,核心都基于Socketpublic InputStream getInputStream() //读取Socket输入流public OutputStream getOutputStream() //读取Socket输出流
核心使用到的类就是以上两个类,但是我们也发现了一些问题:
- 基于io流的输入,效率很差并且对于unicode支持不是很好
- 在SocketServer端,连接和解析在一起,这样会造成资源的浪费。解析层的对象创建会造成性能开销
- 在设计层面,不能很好的兼容多种协议
- 可配置性差
- 异常机制不够完善
- 等等
在下一篇开始我们会逐渐开始解决这些问题