目录
Socaket套接字
UDP数据报套字节编程
1.DatagrameSocket类
DatagramSocaket构造方法:
DatagramSocaket常用方法:
2.DatagramPacket类
DatagramPacket构造方法:
UDP回显服务器实现
UDP服务端实现:
创建一个Socket类对象:
构造方法:
创建start()方法:
异常:
代码展示:
UDP客户端实现:
创建一个Socket对象:
构造方法:
start()方法:
编辑 代码展示:
结果:
服务端和客户端之间的执行流程:
Socaket套接字
Socaket套接字是系统提供的,用于网络通信的技术。是基于TCP/IP协议的网络通信的基本单位。
基于Socaket套接字的网络程序开发就是网络编程。
简单来说,Socket就是操作系统中的一个概念,本质上是一种特殊的文件。
Socaket就是把“网卡”这样的概念给抽象成了文件,把网络通信和文件操作给统一了:
往Socket中写数据,就相当于通过网卡发送数据;从Socket中读数据,就相当于通过网卡接收数据。
Socaket套接字注意事项:
1. 客⼾端和服务端:开发时,经常是基于⼀个主机开启两个进程作为客⼾端和服务端,但真实的场 景,⼀般都是不同主机。
2. 注意 ⽬的IP 和 ⽬的端⼝号,标识了⼀次数据传输时要发送数据的终点主机和进程。
3. Socket编程我们是使⽤ 流套接字 和 数据报套接字,基于传输层的TCP或UDP协议,但应⽤层协议, 也需要考虑,这块我们在后续来说明如何设计应⽤层协议。
4. 关于端⼝被占⽤的问题
5. 如果⼀个进程A已经绑定了⼀个端⼝,再启动⼀个进程B绑定该端⼝,就会报错,这种情况也叫端⼝ 被占⽤。
UDP数据报套字节编程
对于UDP来说,是无连接,面向数据报的特点。即每次都没有建立连接,并且一次发送全部的数据报,一次也接受全部的数据报。
UDP的socktet的api是如何实现的?
java中是由UDP协议通信,主要是使用DatagramSocket类来创建数据报套接字Socket。用DatapramPacket类来作为发送和接收数据报。
1.DatagrameSocket类
java中就是用DatagrameSocket 类来表示UDP Socket文件,用于接收和发送UDP数据报.
DatagramSocaket构造方法:
DatagramSocaket常用方法:
receive和send方法的 DatagramPacket 参数属于 “输出型参数”。
2.DatagramPacket类
DatagramPacket是UDP Socket发送和接收的数据报。
使用这个类来表示UDP数据报,每次传输数据都要以UDP数据报为单位。
DatagramPacket构造方法:
DatagramPacket常用方法:
创建UDP发送数据DatagramPacket responseSocket时,需要指定发送的对方IP和端口号,要传入SocketAddress参数:目的主机的IP地址和端口号,该对象可以使用InteSocketAddress类来创建。
InteSocketAddress类
构造方法:
UDP回显服务器实现
写一个简单的UDP 服务器/客户端通信的程序 :回显服务器(Echo Server):
这个程序没有实现什么功能,就是调用Socket api,让客户端给服务器发送一个请求,请求就是从控制台输入的字符串,服务器再将这个字符串返回给客户端,客户端再将字符串打印显示出来。
DatagramSocket,DatagramPacket类都是再java.net包中的·:
服务器和客户端要创建一个Socket对象,服务器的Socket要显示指定一个端口号,而客户端Socket不需要显示指定(系统会自动分配一个随机端口号)
原因:
UDP服务端实现:
创建一个Socket类对象:
构造方法:
显示指定一个端口号
创建start()方法:
完成Socket的 接收客户端请求,做出响应 返回响应的功能,并循环执行
任务1.创建一个DatagramPacket类对象,接收用户的请求,调用receive方法
requestPacket:
任务2:根据请求 计算响应
任务3:将响应返回给客户端
responsePacket:
这里的第三个参数response.getBytes().length.不能写成response.length():
异常:
在这个程序中,会经常看到SockerException和IOException,要处理一下:
start()代码:
代码展示:
UdpEchoServer
/**
* 实现UDP 回显服务器
*/
class UdpEchoServer{
//创建DatagramSocket类,进行发送数据和接收数据
private DatagramSocket socket=null;
//UDP服务端 构造方法 serverPock: 指定端口号
public UdpEchoServer(int serverPort) throws SocketException {
socket=new DatagramSocket(serverPort);
}
//start方法中,完成Socket的 接收客户端请求,做出响应 返回响应的功能
public void start() throws IOException {
System.out.println("服务器启动");
while(true){//每次循环 ,就是处理一个请求-响应的过程
//1.创建一个DatagramPacket类空对象,用来接收用户的请求
DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
//通过receive接收用户的请求
//此处可能会出现阻塞-》等待用户发送请求
socket.receive(requestPacket);
//2.根据请求 计算响应
//先将请求转换成字符串 方便后面的操作
String request=new String(requestPacket.getData(),0,requestPacket.getLength());
//计算响应
String response=process(request);
//3.将响应返回给客户端
//先将响应打包成DatagramPacket, 指定数据内容、长度、要发给哪个客户端
DatagramPacket responsePacket=new DatagramPacket(response.getBytes(), 0,response.getBytes().length,
requestPacket.getSocketAddress());
//将响应返回给客户端
socket.send(responsePacket);
//打印用户IP 端口号,请求信息 响应信息
System.out.printf("[%s,%d],req:%s,resp:%s\n",requestPacket.getAddress(),requestPacket.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();
}
}
UDP客户端实现:
创建一个Socket对象:
构造方法:
start()方法:
代码展示:
/**
* 实现UDP 回显服务器
* 客户端
*/
class UdpEchoClient1{
private DatagramSocket socket=null;
private String serverIP;//服务端IP
private int serverPort;//服务端 端口号
//构造方法 传入服务端的Ip 端口号 并保存
public UdpEchoClient1(String serverIp,int serverPort) throws SocketException {
socket=new DatagramSocket();
this.serverIP=serverIp;
this.serverPort=serverPort;
}
public void start() throws IOException {
System.out.println("客户端启动");
Scanner scan=new Scanner(System.in);
while(true){
System.out.print("->");
//1.用户从控制台输入请求
if(!scan.hasNext()){
break;
}
//2.读取请求
String request=scan.next();
//3.将请求发送给服务器
//先将请求打包成requestPacket , 指定内容,长度 ;指定要发送的服务器IP,端口号
DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
InetAddress.getByName(serverIP),serverPort);
//发送请求 给服务器
socket.send(requestPacket);
//4.接收服务器的响应
//先创建一个空的DatagramPacket,用来接收服务器的响应
DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
//接收服务器响应
socket.receive(responsePacket);
//将响应转换成String 打印在控制台
String response=new String(responsePacket.getData(),0,responsePacket.getLength());
System.out.println(response);
}
}
public static void main(String[] args) throws IOException {
UdpEchoClient1 udpEchoClient1 = new UdpEchoClient1("127.0.0.1", 9090);
udpEchoClient1.start();
}
}
结果:
客户端和服务端同时启动
DatagramPacket对象,共出现了三种形式:
1.创建空对象,用来存放请求的 参数:字节数组 数组长度
2.服务器 存放请求的响应结果 参数: 响应字节数组 数组长度 客户端IP和端口号
3.客户端 向服务端发送请求 参数: 请求字节数组 数组长度 服务端IP 服务端端口号
服务端和客户端之间的执行流程:
通过UDP服务端模拟实现一个"翻译词典":
参考代码:
/**
* 实现一个词典翻译服务器
* 英 译 汉
*/
class UdpDirectServer extends UdpEchoServer{
//翻译服务器,连接功能与初始的服务器一样,通过继承UdpEchoServer类,
// 重写process方法,实现特有功能
//创建一个哈希表,通过键值对来实现一个查找的功能
private HashMap<String,String> hashMap=new HashMap<>();
public UdpDirectServer(int serverPort) throws SocketException {
super(serverPort);
//填充哈希表
hashMap.put("cat","小猫");
hashMap.put("dog","小狗");
hashMap.put("pig","小猪");
hashMap.put("flag","小鸟");
//......
//真实的翻译词典也是通过大量的键值对来实现查找功能的
}
//重写父类的process方法,实现"翻译"功能
@Override
public String process(String request) {
return hashMap.get(request);
}
public static void main(String[] args) throws IOException {
UdpDirectServer udpDirectServer = new UdpDirectServer(9090);
udpDirectServer.start();
}
}