ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

《网络原理+代码实战:Java Socket编程从零到一》

《网络原理+代码实战:Java Socket编程从零到一》 计算机网络的前世今生随着时代的发展越来越需要计算机之间互相通信共享软件数据即以多个计算机互联完成业务就有了网络互联数据共享的本质是网络运输计算机之间通过网络来传输数据也称为网络通信根据网络互联的规模不同分为局域网和广域网1.局域网与广域网局域网内的主机之间能方便的进行网络通信又称内网。局域网组建网络的方式有以下几种:基于网线直连基于集线器组建基于交换机组建基于交换机和路由器组建通过路由器将多个局域网连接起来在物理上组成了很大范围的网络。广域网内部的局域网都属于其子网。网络通信基础IP与端口网络世界的“门牌号”与“收货人”简单来说IP地址是用来定义主机的网络地址。相当于发送快递的地址。格式是一个32位的二进制数通常用“点分十进制”的方式表示即a.b.c.dabcd都是0~255之间的十进制。端口号是用来定义主机中的进程相当于收货人协议协议是所有网络设备都必须遵守的一组约定最终体现为数据包的格式。因此进行一次网络通信需要涉及到五个非常关键的信息------五元组源IP源端口号目的IP目的端口号协议号协议分层当我们设计完一个协议时会使得这个协议非常复杂非常强大。把一个大的协议拆分成若干个小的协议就是协议分层。分层。只有相邻两层协议之间可以互相交互。上层协议可以调用下层协议下层协议可以给上层协议提供服务。即协议之间的交互不能跨层进行OSI七层模型OSI七层模型是一个逻辑上的定义和规范把网络协议在逻辑上划分为7层。由于体系太复杂了实际真实的网络分层方式是更简化的TCP/IP五层或四层协议模型TCP/IP五层/四层协议模型应用层负责应用程序之间的沟通传输层两个任意设备之间进行通信只考虑起点和终点网络层两个任意设备之间进行通信考虑中间过程数据链路层两个相邻设备之间通信物理层规定了网络通信中一些硬件设施符合的要求网络设备所在的分层对于一台主机操作系统实现了从物理层到应用层也就是TCP/IP五层模型的下四层对于一台路由器工作过程涉及到从物理层到网络层对于交换机工作过程涉及到从物理层到数据链路层这是网络分层对应的协议类型网络编程即网上的主机以编程的形式进行网络通信。对于应用层来说传输层给应用层提供的一组api是socket api。这也是传输层的两大协议。传输层双雄TCP与UDP对比传输层的两个核心协议TCP有连接可靠传输面向字节流全双工UDP无连接不可靠传输面向数据报全双工UDP数据报套接字主要有两大类DatagramSocket和DatagramPacket。通过下方的回显服务器来体会一下~public class UdpEchoServer { //首先需要一个“管道” private DatagramSocket socketnull; public UdpEchoServer(int port) throws SocketException { //因为服务器相当于110啥的“公共电话”他需要有一个专门的端口号。 socketnew DatagramSocket(port); } public void start() throws IOException { System.out.println(服务器启动); while(true){ //1.读取请求并分析 DatagramPacket requestPacketnew DatagramPacket(new byte[4096],4096); socket.receive(requestPacket); //解析,把0和1解析成能看得懂的(要全部解析从0到最后) String requestnew String(requestPacket.getData(),0, requestPacket.getLength()); //2.计算响应 String responseprocess(request); //3.把响应返回给客户端,顺便转化为0和1(相当于警察找人民不知道人民在哪需要地址) DatagramPacket responsePacketnew DatagramPacket(response.getBytes(),response.getBytes().length, requestPacket.getSocketAddress()); socket.send(responsePacket); //4.打印一个日志 System.out.printf([%s:%d] req: %s, resp: %s\n, requestPacket.getAddress().toString(), requestPacket.getPort(), request, response); } } private String process(String request) { return request; } public static void main(String[] args) throws IOException { UdpEchoServer server new UdpEchoServer(9090); server.start(); } }public class UdpEchoClient { private DatagramSocket socketnull; //因为客户端是随机的但每个客户端都需要访问目标地址于是把服务器的地址和端口设置为成员变量 private String serverIp; private int serverPort; public UdpEchoClient(String serverIp,int serverPort) throws SocketException { this.serverIp serverIp; this.serverPort serverPort; socketnew DatagramSocket(); } public void start() throws IOException { Scanner scannernew Scanner(System.in); while(true){ //1.从控制台读取用户的信息 System.out.println(请输入你要发送的内容); if(!scanner.hasNext()){ break; } String requestscanner.next(); //2.把请求发送给服务器(不仅要把内容翻译成机器能看懂的语言getBytes也要把地址Ip翻译成机器能看得懂的InetAddress.getByName(serverIp),serverPort) DatagramPacket requestPacketnew DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(serverIp),serverPort); socket.send(requestPacket); //3.等待接收服务器传回来的响应 DatagramPacket responsePacketnew DatagramPacket(new byte[4096],4096); socket.receive(responsePacket); //4.解析一下看看发的是啥 String responsenew String(responsePacket.getData(),0, responsePacket.getLength()); System.out.println(response); } } public static void main(String[] args) throws IOException { UdpEchoClient clientnew UdpEchoClient(127.0.0.1,9090); client.start(); } }TCP流套接字也有两大类ServerSocket和Socket。ServerSocket 主要是创建TCP服务端的而Socket是为客户端提供的public class TcpEchoServer{ private ServerSocket serverSocketnull; public TcpEchoServer(int port) throws IOException { serverSocketnew ServerSocket(port); } public void start() throws IOException { System.out.println(启动服务器); ExecutorService executorServiceExecutors.newCachedThreadPool(); while(true){ //对于tcp来说需要先处理与服务器的链接 //通过读写clientSocket来和客户端进行通信 /** * accept是接收客户端发来的也就建立链接了如果没有accept就会堵塞 */ while(true){ Socket clientSocketserverSocket.accept(); executorService.submit(()-{ processConnection(clientSocket); }); } } } //处理一个客户端的链接可能包含多个请求 private void processConnection(Socket clientSocket) { System.out.printf([%s:%d] 客户端上线!\n, clientSocket.getInetAddress(), clientSocket.getPort()); try(InputStream inputStreamclientSocket.getInputStream(); OutputStream outputStreamclientSocket.getOutputStream()){ /** * PrintWriter 是“打包快递的人”把你写的字符串打包成字节发到网络上(发送) */ Scanner scannernew Scanner(inputStream); PrintWriter writernew PrintWriter(outputStream); while(true){ //1.读取请求并解析 /** * byte[] requestnew byte[1024];inputStream.read(request);这个相当于提前准备一个容器接住“流” 也可以接住scanner来完成 */ if(!scanner.hasNext()){ System.out.printf([%s:%d] 客户端下线!\n, clientSocket.getInetAddress(), clientSocket.getPort()); break; } String request scanner.next(); //2.根据请求计算响应 String responseprocess(request); //3.返回响应到客户端 writer.println(response); /** * flush() 的作用就是强制把缓冲区里的数据立刻推出去不要等 */ writer.flush(); // 打印日志 System.out.printf([%s:%d] req: %s, resp: %s\n, clientSocket.getInetAddress(), clientSocket.getPort(), request, response); } } catch (IOException e) { throw new RuntimeException(e); } } private String process(String request) { return request; } public static void main(String[] args) throws IOException { TcpEchoServer server new TcpEchoServer(9090); server.start(); } }public class TcpEchoClient { /** * UDP 不需要连接目标无连接所以构造时不需要目标地址 * TCP 是有连接的所以它在构造方法里就拨号连上了目标必须传 IP 和端口 */ private Socket socketnull; public TcpEchoClient(String serverIp,int serverPort) throws IOException { /** * 这一步就相当于是客户端的链接 */ socketnew Socket(serverIp,serverPort); } public void start(){ Scanner scannernew Scanner(System.in); try(InputStream inputStreamsocket.getInputStream(); OutputStream outputStreamsocket.getOutputStream()) { Scanner scanner1new Scanner(inputStream); PrintWriter writenew PrintWriter(outputStream); while(true){ //1.从控制台读取用户输入 String requestscanner.next(); //2.发送给服务器 write.println(request); // 加上刷新缓冲区操作, 才是真正发送数据 write.flush(); //3.读取服务器返回的响应 String responsescanner1.next(); //4.打印到控制台 System.out.println(response); } } catch (IOException e) { throw new RuntimeException(e); } } public static void main(String[] args) throws IOException { TcpEchoClient client new TcpEchoClient(127.0.0.1, 9090); client.start(); } }
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表