目录
网络通信基础
UDP通信
服务器
1.想要使用UDP通信 要先打开DatagramSocket文件 端口号可以手动指定或系统随机分配
2.阻塞等待接收客户端数据;创建DatagramPacket接收客户端传来的数据
3.处理客户端传来的数据,并进行业务处理(这里只演示UDP通信 所以只是回传数据)
4.处理数据成DatagramPacket并发送数据给客户端
整体代码
客户端
1.创建DatagramSocket (这里客户端端口号系统分配即可,不允许和服务器同一端口号)
2.客户端接收用户的数据
3.处理用户数据成DatagramPacket 指定要发送服务器的地址与端口号
4.发送数据给客户端
5.阻塞等待服务器响应
6.处理服务器响应的数据
7.显示数据给用户
整体代码
继承服务器代码,重写业务代码即可
网络通信基础
- 物理层:网络通信的基础设施 运快递的公路
- 数据链路层:两个相邻的节点之间如何传输 两个集散点之间的传输
- 网络层:两个点之间的路径规划 物流公司规划快递的路径
- 传输层:两个点之间的通信(不考虑路径规划) 卖家发货 只考虑起点和终点
- 应用层:数据传输过去之后 如何使用 快递拿到之后如何使用
网络编程的主要工作写应用层的代码,处理应用层的协议数据
从5->1往下传输 每次传输都会依次添加报头 称为封装 QQ1发送
从1->5往上传输 每次传输都会解析去掉报头 QQ2接收
传输层提供两种协议
TCP:有连接,可靠传输,面向字节流,全双工
UDP:无连接,不可靠传输,面向数据包,半双工
可靠传输:数据对方有没有接收到,发送方有感知;打电话就是可靠的,可以知道对方有没有听到。
不可靠传输:数据对方有没有接收到,不管,也不知道;微信就是不可靠,不知道对方有没有看到我的消息。
全双工:双向通信 可以A->B B->A 同时进行
半双工:单向通信 A->B或者B->A 同时只允许一个进行
程序要进行网络通信,需要一个端口号(客户端与服务器的端口号不能相同!)
端口号相当于用来在网络上区分进行的身份标识符
分配端口号有 1.手动指定 2.系统自动分配
UDP通信
UDP的Socket API
DatagramSocket和DatagramPaclet 核心类
socket类本质相当于文件 构造一个DatagramSock对象,相当于打开了一个内核中的socket文件
打开后就可以传输数据了
传输数据已 DatagramPacket为基本单位
InetSocketAddress类 IP地址+端口号
send发送数据 receive接收数据 close关闭数据
DatagramOacket 表示一个UDP数据报 UDP是面向数据报的协议
服务器
1.想要使用UDP通信 要先打开DatagramSocket文件 端口号可以手动指定或系统随机分配
//想要使用UDP服务器 要打开一个文件
private DatagramSocket socket=null;
//创建对象
//服务器IP和端口号是提供给客户端 方便客户端知道地址发送过来
public Test1(int port) throws SocketException {
socket=new DatagramSocket(port);//创建实例 绑定进程端口号
2.阻塞等待接收客户端数据;创建DatagramPacket接收客户端传来的数据
DatagramPacket datagramPacket=new DatagramPacket(new byte[4096],4096);
//客户端发来的请求放到参数datagramPacket 输出性参数
System.out.println("我正在等待!");
socket.receive(datagramPacket);//阻塞等待 客户端发起请求
System.out.println("服务器接收到数据");
3.处理客户端传来的数据,并进行业务处理(这里只演示UDP通信 所以只是回传数据)
//把传来的数据构造成数据 1.获取数据 从0开始构造 构造到数据结尾
String request=new String(datagramPacket.getData(),0,datagramPacket.getLength());
System.out.println("接收到的数据:"+request);
//处理业务
String requst=process(request);
System.out.println("服务器处理数据");
public String process(String s){
return s;
}
4.处理数据成DatagramPacket并发送数据给客户端
//要传回客户端也要把数据构造成DatagramPacket
//把string构造到byte字节 1.字节数据,2.字节长度 3.客户端的id+客户端的端口号
DatagramPacket datagramPackets=new DatagramPacket(request.getBytes(),request.getBytes().length,datagramPacket.getSocketAddress());
//发送数据
socket.send(datagramPackets);
System.out.println("服务器发送数据成功");
System.out.printf("[地址:%s:端口号:%d] 发来数据:%s 服务器响应数据:%s\n",datagramPacket.getAddress().toString(),datagramPacket.getPort(),request,requst);
整体代码
package DemoUDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
//服务端
public class Test1 {
//想要使用UDP服务器 要打开一个文件
private DatagramSocket socket=null;
//创建对象
//服务器IP和端口号是提供给客户端 方便客户端知道地址发送过来
public Test1(int port) throws SocketException {
socket=new DatagramSocket(port);//创建实例 绑定进程端口号
}
public void start() throws IOException {
System.out.println("启动服务器");
while (true){
//创建一个DatagramPacket(创建缓存区,缓存区长度)用来接收客户端发来的请求
DatagramPacket datagramPacket=new DatagramPacket(new byte[4096],4096);
//客户端发来的请求放到参数datagramPacket 输出性参数
System.out.println("我正在等待!");
socket.receive(datagramPacket);//阻塞等待 客户端发起请求
System.out.println("服务器接收到数据");
//把传来的数据构造成数据 1.获取数据 从0开始构造 构造到数据结尾
String request=new String(datagramPacket.getData(),0,datagramPacket.getLength());
System.out.println("接收到的数据:"+request);
//处理业务
String requst=process(request);
System.out.println("服务器处理数据");
//要传回客户端也要把数据构造成DatagramPacket
//把string构造到byte字节 1.字节数据,2.字节长度 3.客户端的id+客户端的端口号
DatagramPacket datagramPackets=new DatagramPacket(request.getBytes(),request.getBytes().length,datagramPacket.getSocketAddress());
//发送数据
socket.send(datagramPackets);
System.out.println("服务器发送数据成功");
System.out.printf("[地址:%s:端口号:%d] 发来数据:%s 服务器响应数据:%s\n",datagramPacket.getAddress().toString(),datagramPacket.getPort(),request,requst);
}
}
public String process(String s){
return s;
}
public static void main(String[] args) throws IOException {
//端口号范围 0--65535 1024以下的端口是系统用的 尽量用1024以上 65535以下
Test1 test1=new Test1(8080);
test1.start();
}
}
客户端
1.创建DatagramSocket (这里客户端端口号系统分配即可,不允许和服务器同一端口号)
DatagramSocket Socket=null;
//客户端端口号需要系统自动分配 不能指定与服务器端口号一样,不然会抢占服务器端口号 导致后启动的一端无法启动
public Test2() throws SocketException {
Socket=new DatagramSocket();
}
2.客户端接收用户的数据
Scanner scanner=new Scanner(System.in);
System.out.println("客户端输入数据:>");
String Data=scanner.nextLine();
3.处理用户数据成DatagramPacket 指定要发送服务器的地址与端口号
//处理用户数据
//1.把string类型处理成byte字节数据 datagramPacket类型 里面附带发送地址和发送对方的端口号
DatagramPacket datagramPacket=new DatagramPacket(Data.getBytes(),Data.getBytes().length, InetAddress.getByName("127.0.0.1"),8080);
System.out.println("客户端处理数据");
4.发送数据给客户端
//发送数据
Socket.send(datagramPacket);
System.out.println("客户端发送数据");
5.阻塞等待服务器响应
//阻塞等待服务器的响应数据
DatagramPacket datagramPackets=new DatagramPacket(new byte[1024],1024);
Socket.receive(datagramPackets);
System.out.println("客户端接收服务器响应数据");
6.处理服务器响应的数据
//处理服务器响应的数据
String Datas=new String(datagramPackets.getData(),0,datagramPackets.getLength());
System.out.println("客户端处理数据");
7.显示数据给用户
System.out.printf("服务器响应数据:%s\n",Datas);
整体代码
package DemoUDP;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
//客户端
public class Test2 {
DatagramSocket Socket=null;
//客户端端口号需要系统自动分配 不能指定与服务器端口号一样,不然会抢占服务器端口号 导致后启动的一端无法启动
public Test2() throws SocketException {
Socket=new DatagramSocket();
}
public void start() throws IOException {
while (true){
//接收用户数据
Scanner scanner=new Scanner(System.in);
System.out.println("客户端输入数据:>");
String Data=scanner.nextLine();
//处理用户数据
//1.把string类型处理成byte字节数据 datagramPacket类型 里面附带发送地址和发送对方的端口号
DatagramPacket datagramPacket=new DatagramPacket(Data.getBytes(),Data.getBytes().length, InetAddress.getByName("127.0.0.1"),8080);
System.out.println("客户端处理数据");
//发送数据
Socket.send(datagramPacket);
System.out.println("客户端发送数据");
//阻塞等待服务器的响应数据
DatagramPacket datagramPackets=new DatagramPacket(new byte[1024],1024);
Socket.receive(datagramPackets);
System.out.println("客户端接收服务器响应数据");
//处理服务器响应的数据
String Datas=new String(datagramPackets.getData(),0,datagramPackets.getLength());
System.out.println("客户端处理数据");
//显示处理后的数据给用户
System.out.printf("服务器响应数据:%s\n",Datas);
}
}
public static void main(String[] args) throws IOException {
Test2 test2=new Test2();
test2.start();
}
}
继承服务器代码,重写业务代码即可
package DemoUDP;
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
public class Test3 extends Test1{
public Test3(int port) throws SocketException {
super(port);
}
@Override
public String process(String s) {
Map<String,String> dic=new HashMap<String,String>();
dic.put("cat","猫");
return dic.getOrDefault(s,"此单词还未更新");
}
public static void main(String[] args) throws IOException {
Test3 test3=new Test3(8080);
test3.start();
}
}
指定客户端多开
之后就可以同时运行多个客户端访问服务器