JavaEE初阶 --网络编程

张开发
2026/5/5 6:37:26 15 分钟阅读

分享文章

JavaEE初阶 --网络编程
一.为什么要网络编程用户在浏览器打开视频网站时实际是通过网络获取到的网络资源所有的网络资源都是通过网络编程进行数据传输的。二.Socket套接字1.概念Socket套接字本质上是一个编程接口是由传输层给应用层提供的。当俩台设备进行通信时Socket内部封装了通信的五元组。内核通过五元组唯一标识一条路径确保数据能够准确送达到指定设备目的IP的指定进程目的端口。2.分类我们主要学习的是流套接字使用传输层TCP协议和数据报套接字使用传输层UDP协议1数据包套接字特点无连接面向数据包不可靠传输全双工有接受缓冲区无发送缓冲区.一次最多传送64kb(讲UDP的结构可知道)2流套接字特点有连接面向字节流可靠传输全双工既有接受缓冲区又有发送缓冲区传输数据大小不限。3.名词解释1)有连接和无连接这里的连接是逻辑上的连接而不是物理上的连接。在TCP协议中如果设备A和设备B进行通信就得先建立连接让A保存B的相关信息B也保存A的相关信息彼此之间知道自己连接的是谁。在UDP协议中是无连接俩台设备不会保存对端的相关信息直接根据五元组中的目标IP和端口转发数据包因此无需建立链路也能通信。2可靠传输和不可靠传输网络上是非常容易出现数据丢失的情况丢包如光信号和电信号容易遭受到外部环境的影响。可靠传输的意思不是让数据100%到达目的地而是在出现丢包的情况下能够知道然后在一定条件下进行重传。而不可靠传输是把数据发出去后就直接不管了3面向字节流和面像数据报面向字节流代表传输数据的基本单位为字节但会出现粘包问题讲TCP的结构会讲面向数据报代表传输数据的基本单位为数据报,不会出现粘包问题。4全双工和半双工全双工代表双向通信既能读又能写半双工代表单向通信要么读要么写总结对于TCP而言通信前需要通过三次握手TCP协议会讲在内核中建立一条逻辑链路即维持双方的状态同步以保证可靠传输而对于UDP内核不维护对端状态直接根据五元组中的目标地址转发数据包因此无需建立链路也能通信。三.网络编程1.UDP数据报套接字编程API介绍1DatagramSocket是UDP Socket,用于发送和接受UDP数据包构造方法普通方法2DatagramPacket是UDP Socket发送和接受的数据报构造方式普通方法使用代码import java.io.IOException; import java.net.*; public class UDPEchoServer { private DatagramSocket socket null; //指定ip public UDPEchoServer(String ip, int port) throws UnknownHostException, SocketException { socket new DatagramSocket(port,InetAddress.getByName(ip)); } //不指定ip代表绑定本机所有ip public UDPEchoServer(int port) throws SocketException { socket new DatagramSocket(port); } public void start() throws IOException { System.out.println(........服务端启动); // 不断处理请求 while (true){ DatagramPacket requestPacket new DatagramPacket(new byte[4096],4096); // 读取请求 socket.receive(requestPacket); // 处理请求,把字节数组转化为字符串形式,这里得传有效长度不能传requestPacket.getData().length String request new String(requestPacket.getData(),0, requestPacket.getLength()); String response process(request); // 响应请求 DatagramPacket responsePacket new DatagramPacket( response.getBytes(),response.getBytes().length,//这里传的是字节数不能传response.length requestPacket.getAddress(),requestPacket.getPort()); socket.send(responsePacket); System.out.println(客户端requestPacket.getPort()requestPacket.getAddress()发出请求); System.out.printf(回复%s\n,response); } } private String process(String request) { //为回显服务器不做处理 return request; } public static void main(String[] args) throws IOException { UDPEchoServer echoServer new UDPEchoServer(9090); echoServer.start(); } }import java.io.IOException; import java.net.*; import java.util.Scanner; public class UDPEchoClient { private DatagramSocket socket null; private String serverIp; private int serverPort; public UDPEchoClient(String serverIp, int serverPort) throws SocketException { this.serverIp serverIp; this.serverPort serverPort; //找空闲端口 socket new DatagramSocket(); } public void start() throws IOException { Scanner scanner new Scanner(System.in); while (true){ //用户输入请求 String request scanner.next(); //发送请求 DatagramPacket requestPacket new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(serverIp),serverPort); socket.send(requestPacket); // 接收响应 DatagramPacket responsePacket new DatagramPacket(new byte[4096],4096); socket.receive(responsePacket); String response new String(responsePacket.getData(), 0,responsePacket.getLength()); System.out.println(response:response); } } public static void main(String[] args) throws IOException { UDPEchoClient udpEchoClient new UDPEchoClient(10.2.14.62,9090); udpEchoClient.start(); } }2.TCP套接字编程API介绍1ServerSocket是创建TCP服务端Socket构造方法普通方法2SocketSocket 是客⼾端Socket或服务端中接收到客⼾端建⽴连接accept⽅法的请求后返回的服 务端Socket。 不管是客⼾端还是服务端Socket都是双⽅建⽴连接以后保存的对端信息及⽤来与对⽅收发数据 的。构造方法普通方法使用代码import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TCPEchoServer { private ServerSocket socket null; public TCPEchoServer(int port) throws IOException { socket new ServerSocket(port); } public void start() throws IOException { System.out.println(服务端启动); ExecutorService executorService Executors.newCachedThreadPool(); //每一个连接处理一个客户端 while (true){ Socket clientSocket socket.accept(); executorService.submit(()-{ System.out.println(客户端启动: clientSocket.getInetAddress() clientSocket.getPort()); processConnect(clientSocket); }); } // while (true){ // Socket clientSocket socket.accept(); // Thread thread new Thread(()-{ // System.out.println(客户端启动: // clientSocket.getInetAddress() clientSocket.getPort()); // processConnect(clientSocket); // }); // thread.start(); // } } private void processConnect(Socket clientSocket) { try(InputStream inputStream clientSocket.getInputStream(); OutputStream outputStream clientSocket.getOutputStream()){ Scanner scanner new Scanner(inputStream); PrintWriter writer new PrintWriter(outputStream); while (true){ if(!scanner.hasNext()){ System.out.println(客户端退出 clientSocket.getInetAddress() clientSocket.getPort()); break; } String request scanner.next(); String response process(request); writer.println(response); writer.flush(); System.out.println(客户端clientSocket.getInetAddress() clientSocket.getPort()发来请求); System.out.println(回复response); } } catch (IOException e) { throw new RuntimeException(e); }finally { try { clientSocket.close(); } 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(); } }import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class TCPEchoClient { private Socket clientSocket null; public TCPEchoClient(String serverIp,int serverPort) throws IOException { clientSocket new Socket(serverIp,serverPort); System.out.println(客户端上线clientSocket.getLocalAddress() clientSocket.getLocalPort()); } public void start(){ try(InputStream inputStream clientSocket.getInputStream(); OutputStream outputStream clientSocket.getOutputStream()){ Scanner scannerRead new Scanner(inputStream); PrintWriter writer new PrintWriter(outputStream); Scanner scannerWrite new Scanner(System.in); while (true){ System.out.println(请输入请求---》); String request scannerWrite.next(); writer.println(request); writer.flush(); String response scannerRead.next(); 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(); } }注意如果客户端进一步增加就会产生大量的线程。为了处理这个问题操作系统内部内置了IO多路复用----本质上是一个线程负责处理多个客户端的请求。

更多文章