目录
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;//服务端IPprivate 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方法,实现"翻译"功能@Overridepublic String process(String request) {return hashMap.get(request);}public static void main(String[] args) throws IOException {UdpDirectServer udpDirectServer = new UdpDirectServer(9090);udpDirectServer.start();}}