javaSE————网络编程套接字
网络编程套接字~~~~~
好久没更新啦,蓝桥杯爆掉了,从今天开始爆更嗷;
1,网络编程基础
为啥要有网络编程呢,我们进行网络通信就是为了获取丰富的网络资源,说实话真的很神奇,想想我们躺在床上,通过网络,访问到世界上成千上万的人做好的网络资源,我们甚至能看到一辈子都看不到的景色,这些资源本质上都是二进制资源或者是文本资源,我们通过网络可以让很多人来访问,这个就是网络编程,当年的网络就是个看报的,谁能想到发展到这样呢?
网络编程的概念:网络上的主机,通过不同的进程,以编程的方式实现网络通信;
同一个主机下的不同进程实现网络通信也是网络编程;
网络编程的基本概念:
接收端:数据接收端进程,目标主机;
发送端:数据发送端进程,源主机;
收发端:发送接收两端;
请求:请求数据的发送;
响应:响应数据的发送;
就像我们去餐厅点一份蛋炒饭就是请求,厨师给我们拿来蛋炒饭就是回应;
服务端:提供服务的一方,返回服务资源;
客户端:获取服务的一方;
2,Socket套接字
Socket就是套接字,啥是套接字,这名起的,Socket套接字是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本单元,基于Socket套接字的网络程序开发就是网络编程;
Socket套接字主要针对传输层协议划分为三类:
我们这里就学两个核心协议
1,TCP,有连接,可靠传输,面向字节流,全双工;
2,UDP,无连接,不可靠传输,面向数据报,全双工;
这里的有连接和无连接都是抽象的概念,虚拟上的连接;
TCP协议保存了对端的信息,A和B通信,A和B先建立连接,A保存了B的信息,B也保存了A的信息,他们彼此都知道谁与自己建立的连接,而UDP不保存对方的信息;
可靠传输和不可靠传输是什么呢?
网络上,数据的传输是会发生丢包的情况的,可能会受到外界的干扰,那么可靠传输就能避免这样的丢包吗,事实上是不能的,可靠传输只是保证尽可能提高传输成功的概率,如果出现了丢包,也能感知到,不可靠传输的话就是把数据发送之后就不管了,那么这样的话我们就使用可靠传输就好了呀,还要UDP干嘛呢,凡是必有代价,UDP的话速度会更快;
面向字节流和面向数据报呢?
面向字节流:读写数据的时候,以字节为单位;
面向数据报:读写数据的时候,以一个数据报为单位;
全双工和半双工呢?
全双工:一个通信联络,能读也能写;
半双工:只支持单向通信,要么读,要么写;
我们使用Socket api来进行网络编程,我们之前提到计算机中的“文件”有狭义和广义的概念,硬件设备可以抽象成文件,统一管理;电脑上的网卡就是Socket文件;
3,UDP数据报套接字编程
我们先来介绍UDP需要的API:
DatagramSocket
UDP的Socket用于接收和发送UDP数据报;
构造方法:
方法:
DatagramPacket
datagramPacket是UDP socket发送和接收的数据报;
构造方法:
构造一个DatagramPacket用来接收数据报,接收的数据呢保存在字节数组中,接收指定的长度
方法:
从接收的数据报中,获取发送端主机IP;或者从发送的数据报中,获取接收端主机IP;
讲完方法了,我们来模拟一个回显服务器,这里就是模拟,回显服务器就是自问自答;
我们来用UDP模拟一下:
import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.Socket;import java.net.SocketException;public class UdpEchoServer { private DatagramSocket socket = null; public UdpEchoServer(int port) throws SocketException { socket = new DatagramSocket(port);//指定端口号,让服务器来使用 } public void start() throws IOException { //启动服务器 while(true){ //循环一次,就意味着处理了一次请求 //1读取请求并解析 DatagramPacket packet = new DatagramPacket(new byte[4090],4090); socket.receive(packet); String request = new String(packet.getData(),0,packet.getLength()); //2根据请求计算响应 String response = process(request); //3把响应返回给客户端 DatagramPacket packet1 = new DatagramPacket(response.getBytes(),response.getBytes().length ,packet.getSocketAddress()); socket.send(packet1); //4打印日志 System.out.printf(\"[%s:%d] req: %s, resp: %s\\n\", packet.getAddress().toString(), packet.getPort(), request, response); } } public String process(String request){ return request; } public static void main(String[] args) throws IOException { UdpEchoServer udpEchoServer = new UdpEchoServer(9090); udpEchoServer.start(); }}
模拟服务器:难点用注释标注了,看不明白就来私信我!
接下来实现客户端代码:
import java.io.IOException;import java.net.*;import java.util.Scanner;public class UdpEchoClient { private DatagramSocket socket = null; private String SeverIp; private int SeverPort; public UdpEchoClient(String IP,int port) throws SocketException { this.SeverIp = IP; this.SeverPort = port; socket = new DatagramSocket(); } public void start() throws IOException { Scanner scanner = new Scanner(System.in); while(true){ System.out.println(\"请输入要发送的内容\"); while(!scanner.hasNext()){ break; } String request = scanner.nextLine(); DatagramPacket datagramPacket = new DatagramPacket(request.getBytes(),request.getBytes().length , InetAddress.getByName(SeverIp),SeverPort); socket.send(datagramPacket); DatagramPacket datagramPacket1 = new DatagramPacket(new byte[4090],4090); socket.receive(datagramPacket1); String response = new String(datagramPacket1.getData(),0,datagramPacket1.getLength()); System.out.println(response); } } public static void main(String[] args) throws IOException { UdpEchoClient udpEchoClient = new UdpEchoClient(\"127.0.0.1\",9090); udpEchoClient.start(); }}
我们把两个代码的都运行下
客户端
服务器
4,TCP流套接字编程
接下来我们来实现TCP的网络编程,还是先来学习一下方法:
SeverSocket
SeverSocket呢是创建TCP服务端Socket的ApI;
构造方法:
方法:
Socket
socket是客户端Socket,或服务端中接收到客户端建立连接(accept)的请求后,返回的服务端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.ExecutorService;import java.util.concurrent.Executors;public class TcpEchoServer { private ServerSocket serverSocket = null; public TcpEchoServer(int port) throws IOException { serverSocket = new ServerSocket(port); } public void start() throws IOException { System.out.println(\"启动服务器\"); ExecutorService executorService = Executors.newCachedThreadPool(); while(true){ Socket socketClient = serverSocket.accept(); executorService.submit(()->{ try { processConnection(socketClient); } catch (IOException e) { throw new RuntimeException(e); } }); } } public void processConnection(Socket socketClient) throws IOException { System.out.println(\"客户端上线\"+ socketClient.getInetAddress()+socketClient.getPort()); try(InputStream inputStream = socketClient.getInputStream(); OutputStream outputStream = socketClient.getOutputStream()){ Scanner scanner = new Scanner(inputStream); PrintWriter printWriter = new PrintWriter(outputStream); while (true){ if(!scanner.hasNext()){ System.out.println(\"客户端下线\"+ socketClient.getInetAddress()+socketClient.getPort()); break; } String request = scanner.nextLine(); String response = process(request); printWriter.println(response); printWriter.flush(); System.out.printf(\"[%s:%d] req: %s, resp: %s\\n\", socketClient.getInetAddress(), socketClient.getPort(), request, response); } } } public String process(String request){ return request; } public static void main(String[] args) throws IOException { TcpEchoServer tcpEchoServer = new TcpEchoServer(9090); tcpEchoServer.start(); }}
这里引入线程池来处理多个请求,避免其他请求发来处理不了的情况;
客户端:
import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.Scanner;public class TcpEchoClient { private Socket socket = null; public TcpEchoClient(String IP,int port) throws IOException { socket = new Socket(IP,port); } public void start() throws IOException { Scanner scanner = new Scanner(System.in); try(InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream()){ Scanner scanner1 = new Scanner(inputStream); PrintWriter printWriter = new PrintWriter(outputStream); while(true){ System.out.println(\"请输入要发送的信息\"); String request = scanner.nextLine(); printWriter.println(request); printWriter.flush(); String response = scanner1.nextLine(); System.out.println(response); } } } public static void main(String[] args) throws IOException { TcpEchoClient tcpEchoClient = new TcpEchoClient(\"127.0.0.1\",9090); tcpEchoClient.start(); }}