1、TCP与UDP区别
TCP:有连接,可靠传输,面向字节流,全双工
UDP:无连接,不可靠传输,面向数据报,全双工
2、UDP sockeAPI的核心类
DatagramSocket:相当于对socket文件进行封装,有了socket文件以后,就可以真正操作网卡,发送和接收数据。
DatagramPacket:发送和接收数据的基本单位。
close方法,在下面代码中没有用到,文件打开之后要及时关闭,为啥下列代码不进行关闭呢?
代码中的socket对象,生命周期伴随整个进程,因此进程结束前,提前关闭socket对象不合适,当进程结束时,对应的PCB也没了,PCB文件上的文件描述符表也没了,也就相当于关闭了。
3、客户端和服务器的工作流程
一、回显
1、服务器
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;public class UdpEchoServer {//要想创建udp服务器,首先要打开一个socket文件private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}//启动服务器public void start() throws IOException {System.out.println("服务器启动!");while(true){//1、读取客户端发来的请求DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);//2、对请求进行解析,把datagramPacket 转成一个stringString request = new String(requestPacket.getData(),0, requestPacket.getLength());//3、根据请求,处理响应,虽然咱们这个是回显服务器,但还是可以搞个单独的方法来做这个事情String response = process(request);//4、把响应构造成 DatagramPacket 对象返回给客户端// 构造响应对象,要搞清楚,对象要发给谁(谁给咱们发的请求,就把响应发给谁!!)DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());//5、把这个DatagramPacket 对象返回给客户端socket.send(responsePacket);System.out.printf("[%s:%d] req=%s ; resp=%s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);}}//通过这个方法,实现根据请求计算响应这个过程//但是由于是回显服务器,所以不涉及到其他逻辑,但如果是其他服务器,就可以在 process 里面,来加上一些其他逻辑的处理public String process(String req){return req;}public static void main(String[] args) throws IOException {//main方法是真正启动服务器,这个端口号说是随便写,但是也是有范围的,0 - 65535//一般来说1024以下的端口,都是系统保留,一般不使用//因此咱们写代码,端口号尽量选择 1024 - 65535UdpEchoServer server = new UdpEchoServer(8000);server.start();}
}
2、客户端
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;public UdpEchoClient() throws SocketException {//客户端的端口号,一般是由操作系统自动分配,虽然手动指定也行,习惯上还是自动分配比较好socket = new DatagramSocket();}public void start() throws IOException {Scanner scanner = new Scanner(System.in);while (true) {//1、让客户端从控制台读取一个请求数据System.out.print("> ");String request = scanner.next();//2、把这个字符串请求发送给服务器,构造 DatagramPocket// 构造的DatagramPocket 既要包含传输的数据 ,又要包含把数据发送到哪里DatagramPacket requestPocket = new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName("127.0.0.1"),8000);socket.send(requestPocket);//4、从服务器读取响应数据DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);//5、把响应数据获取出来,转成字符串String response = new String(responsePacket.getData(),0,responsePacket.getLength());System.out.printf("req:%s;resp:%s\n",request,response);}}public static void main(String[] args) throws IOException {UdpEchoClient udpEchoClient = new UdpEchoClient();udpEchoClient.start();}
}
二、翻译服务器
在回显服务器的基础上,运用hash MAP
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;public class UdpDictServer extends UdpEchoServer{private Map<String,String> dict = new HashMap<>();public UdpDictServer(int port) throws SocketException {super(port);dict.put("cat","小猫");dict.put("dog","小狗");dict.put("baobao","瑾瑾");}//和 UdpEchoServer 相比,只是process不同,就重写这个方法即可@Overridepublic String process(String req) {return dict.getOrDefault(req,"这个词俺也不知道");}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpDictServer(8000);server.start();}
}