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 转成一个string
String 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 - 65535
UdpEchoServer 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不同,就重写这个方法即可
@Override
public String process(String req) {
return dict.getOrDefault(req,"这个词俺也不知道");
}
public static void main(String[] args) throws IOException {
UdpEchoServer server = new UdpDictServer(8000);
server.start();
}
}