但使龙城飞将在,只缘身在此山中

之前在 BIO、NIO 入门(Netty 先导) 一文中聊了 socket ,本文想把视野拉大,从计算机网络的纬度来聊聊 socket

温故而知新,聊聊网络模型

上图对比给出了 ISO(International Standardization Organization 国际标准化组织)的 OSI (Open System Interconnect Reference Model 开放式系统互联参考模型)七层网络参考模型,这个模型是标准,是参考,而现在使用最广的实现是 TCP/IP 的四层模型。

Tips:这里提一下,网上有说 TCP/IP 四层模型的,也有说五层的,区别在于 四层是把 数据链路层 和 物理层 合并为一个 网络接口层,这两种说法都不为错。

聊点真实的

感觉上图说的还是有点虚,懂了但是好像没完全懂。那这里我们聊点真实的,说说我们真正在用的 TCP/IP 网络模型,以 五层分层为例,这样更清楚一些。

总的来说,我们日常编程玩的大部分都在 应用层 和 传输层 这两块。OK 这里提到 Socket 编程,那么 Socket 在哪?用来干嘛?继续来点真实的

说说 Socket

所谓 Socket 编程,其实就是在串联 应用层传输层以达到我们的需求目的。主要就是在操作 传输层的协议,而我们主流的传输层协议就是 TCP 和 UDP 所以重点关注这两个协议即可。

不得不说的 TCP 和 UDP

时常被问到的一个问题:TCP 和 UDP 什么区别? 通常答案是这样的

TCP 是面向连接的;UDP 面向无连接。

TCP 是可靠的,无差错、不丢失、保证顺序;UDP 不可靠,不保证

TCP 面向字节流,发送时是一个流;UDP 面向数据报 ,一个一个发送

TCP 可以提供 流量控制,拥塞控制;UDP 没有

以上大概是常用的回答了,但是对于自己理解来说,似乎总有些说不清道不明的迷糊在里面。比如

连接到底是什么?真的是在网线中维系了这样一种抽象的链路吗?

不是的,”连接“ 意思上感觉是通路,其实其只存在于两端,即需要通信的两端。

建立连接其实就是在通信两端建立一种数据结构,然后维持这种数据结构,以保证通信双方可以互相识别对方发送过来的信息,并用这样的数据结构保证面向连接的特性。

来点真实的:连接在两端,而非通路。可以理解为两端数据结构的协调,这个数据结构类比 Java 可以理解为 Class

两边数据结构状态一致,符合 TCP 的规则,那就认为连接存在,如果对不上就是连接断了。

而所谓的可靠、顺序、流传输,这些也都是通过两端的数据结构来保证。可靠是数据结构在点名,顺序是数据结构进行了排序、流传输是数据结构对单个包进行了归并统一发送。

生活的例子:

我觉得很形象的就是我们买东西时 收发快递 ,你与商家就是两端,网络层就相当于你们彼此知道地址,而发送包裹交给物流,具体发生什么事你们根本不知道,你们只关心结果,而 ”数据结构“ 就是商家和买家各自对于包裹异常所作出的行为补正,用于保证快递正确到达且完好无损。

回到 Socket 编程

经过上面的铺垫,可以知道,Socket 编程其实就是端对端的编程,其控制的是端上的逻辑,有时候我们又会听到一起其他的相关名词。如: Socket 文件、Socket 句柄。 这个其实是在我们最常用的 Linux 服务器上,Socket 就是以一种文件的形式存在的,所以收到内存的大小的限制,Socket 连接数同样也是有限制的,不然迟早要冲垮你的服务器。

下图是 Socket 针对 TCP 协议 Java 版的伪代码。其他语言逻辑类似。

这里 服务端 绑定好端口,调用 accept 方法,等待一个连接请求,完成 TCP 的三次握手,成功后会返回这个链接的 Socket 对象,那么如果需要处理多个连接就需要多次调用 accept 方法,所以经常可以看到 accept 方法是套在循环里的。

可以发现客户端在创建 Socket 连接的时候似乎不需要绑定端口,这是因为系统会为其随机分配一个端口进行连接,因为客户端只有我们自己在用,所以并不关心客户端端口是多少。

用 Socket 实现 RPC 远程服务调用

ok ,基于理论,这里我用 Java 简单实现了一个 RPC 接口,给大家提供一个实际的参考。

服务端统一接口

public interface RpcServer {void stop();void start() throws IOException;void register(Class<?> serviceInterface, Class<?> impl);boolean isRunning();int getPort();}

服务端默认实现

public class DefaultServer implements RpcServer {private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());private static final HashMap<String, Class> serviceRegistry = new HashMap<String, Class>();private static boolean isRunning = false;private int port;public DefaultServer(int port) {this.port = port;}@Overridepublic void stop() {isRunning = false;executor.shutdown();}@Overridepublic void start() throws IOException {System.out.println("start server");ServerSocket serverSocket = new ServerSocket();serverSocket.bind(new InetSocketAddress(port));System.out.println("====已注册服务====");for (Map.Entry<String, Class> entry : serviceRegistry.entrySet()) {System.out.println("注册服务名:"+entry.getKey()+" 实现:"+entry.getValue());}System.out.println("==========");try {while (true) {executor.execute(new ServerTask(serverSocket.accept()));}} finally {serverSocket.close();}}@Overridepublic void register(Class<?> serviceInterface, Class<?> impl) {serviceRegistry.put(serviceInterface.getName(), impl);}@Overridepublic boolean isRunning() {return isRunning;}@Overridepublic int getPort() {return port;}private class ServerTask implements Runnable {private Socket socket;public ServerTask(Socket socket) {this.socket = socket;}@Overridepublic void run() {ObjectInputStream inputStream = null;ObjectOutputStream outputStream = null;try {inputStream = new ObjectInputStream(socket.getInputStream());String serviceName = inputStream.readUTF();String methodName = inputStream.readUTF();Class<?>[] parameterTypes = (Class<?>[]) inputStream.readObject();Object[] arguments = (Object[]) inputStream.readObject();Class<?> serviceClass = serviceRegistry.get(serviceName);if (serviceClass == null) {throw new ClassNotFoundException(serviceName + " not found");}Method method = serviceClass.getMethod(methodName, parameterTypes);Object result = method.invoke(serviceClass.newInstance(), arguments);outputStream = new ObjectOutputStream(socket.getOutputStream());outputStream.writeObject(result);} catch (Exception e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}}
}

客户端实现

public class RPCClient<T> {public static  <T> T getRemoteProxyObj(final Class<?> serviceInterface, final InetSocketAddress addr) {return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface},new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Socket socket = null;ObjectOutputStream output = null;ObjectInputStream input = null;try {socket = new Socket();socket.connect(addr);output = new ObjectOutputStream(socket.getOutputStream());output.writeUTF(serviceInterface.getName());output.writeUTF(method.getName());output.writeObject(method.getParameterTypes());output.writeObject(args);// 4.同步阻塞等待服务器返回应答,获取应答后返回input = new ObjectInputStream(socket.getInputStream());return input.readObject();} catch (Exception e) {e.printStackTrace();} finally {if (socket != null) socket.close();if (output != null) output.close();if (input != null) input.close();}return null;}});}}

demo 类

public interface Demo {String getName(String name);
}
public class DemoAImpl implements Demo{@Overridepublic String getName(String name) {return "AAAAA "+name;}
}

提供服务

public class ProviderTest {public static void main(String[] args) throws IOException {RpcServer rpcServer = new DefaultServer(8088);rpcServer.register(Demo.class, DemoAImpl.class);rpcServer.start();}
}

客户端调用

public class RpcTest {public static void main(String[] args) {Demo demo = RPCClient.getRemoteProxyObj(Demo.class, new InetSocketAddress("localhost", 8088));System.out.println(demo.getName("nice"));}
}

说明一下

这种编程方式其实是非常原始的,有极大的改进空间,比如用 NIO 或者 Netty 都可以进行优化 BIO、NIO 入门(Netty 先导),还有数据传输的方式,篇幅原因,这里埋个坑,我们下期继续聊。

千回百转,这里是 dying 搁浅。

网络编程之 Socket 编程 一文看懂相关推荐

  1. 网络编程之 socket编程

    socket编程(基于linux下的网络编程) 提起网络编程那么我们就不得不说一下socket编程了(本博客主要是围绕下面这本书展开的). 感谢bingo大佬提供的书籍 链接: https://pan ...

  2. java网络编程之Socket编程

    概念 网络编程分为BIO(传统IO).NIO.AIO.Socket编程属于BIO这种传统IO. InetAddress java.net.InetAddress是JAVA中管理IP地址的类,常用 pu ...

  3. Python网络编程之socket编程

    什么是Socket? Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面 ...

  4. linux网络编程之socket编程(六)

    经过一个国庆长假,又有一段时间没有写博文了,今天继续对linux网络编程进行学习,如今的北京又全面进入雾霾天气了,让我突然想到了一句名句:"真爱生活,珍惜生命",好了,言归正传. ...

  5. linux网络编程之Socket编程

    (1)socket套接字 1)在linux环境下,socket用于表示进程间网络通信的特殊文件类型,其本质是内核借助缓冲区形成的伪文件(不占磁盘空间,除此之外还有二进制文件,管道,字符文件). 2)伪 ...

  6. 网络编程+go+java_GO语言的进阶之路-网络编程之socket

    GO语言的进阶之路-网络编程之socket 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是socket; 在说socket之前,我们要对两个概念要有所了解,就是IP和端口 ...

  7. 网络编程之socket

    网络编程之socket 看到本篇文章的题目是不是很疑惑,what is this?,不要着急,但是记住一说网络编程,你就想socket,socket是实现网络编程的工具,那么什么是socket,什么是 ...

  8. GO语言的进阶之路-网络编程之socket

    GO语言的进阶之路-网络编程之socket 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是socket; 在说socket之前,我们要对两个概念要有所了解,就是IP和端口 ...

  9. 浅谈Java网络编程之Socket (2)

    <浅谈Java网络编程之Socket (1)>中我们已经和大家说到客户端的网络编程,下面和大家分享的是服务器的实现代码. import java.net.*; import java.io ...

最新文章

  1. PAT_B_1006 换个格式输出整数
  2. 图神经网络三剑客:GCN、GAT与GraphSAGE
  3. Distributed transactions with multiple databases, Spring Boot, Spring Data JPA and Atomikos
  4. java get image获取根路径_Java 获取资源文件路径
  5. TensorFlow实现简单的卷积网络
  6. dede article_eidt_action.php 5.7,织梦dedecmsV5.7后台编辑文章中文标题发布失败的解决方法...
  7. [Java] 蓝桥杯ALGO-125 算法训练 王、后传说
  8. 【LeetCode】124. Binary Tree Maximum Path Sum
  9. 超变单职业传奇脱机辅助制作视频教程
  10. 说ViewHolder
  11. 电机与拖动matlab仿...,电机与拖动基础及MATLAB仿真习题答案(第四章)
  12. 三毛的创作姿态与文体选择
  13. 【houdini 基础】Ramp 参数
  14. 10.SpringBoot学习(十)——JDBC之 Spring Boot Jpa
  15. 进口十大旋转编码器厂商
  16. system32下 exe文件作用
  17. 如何在A4相纸上打印4张5寸相片
  18. Ubuntu+Tesla M40上OpenCL问题解决过程
  19. 最新域名防红程序源码 采用小Q防红
  20. Chrome网页接口测试工具

热门文章

  1. 黑马程序员--“云计算”逆天!月薪14000大神的经验爆料,不看后悔!
  2. GitLab 14 登录
  3. 5、C语言——前言(基础知识)
  4. redis系列-redis基础知识总结
  5. mathtype公式中特殊符号word无法正常显示
  6. vim退出visual模式
  7. 方舟服务器目前维修中,明日方舟:游戏最近隔三差五维护,只能说——发家致富、全靠维护...
  8. oracle 获取最大id
  9. 【漫画】分布式锁究竟可以多少并发?
  10. Linux下配置jdk11