JAVA基础学习day24--Socket基础一UDP与TCP的基本使用
一、网络模型
1.1、OIS参考模型
1.2、TCP/IP参考模型
1.3、网络通讯要素
IP地址:IPV4/IPV6
端口号:0-65535,一般0-1024,都被系统占用,mysql:3306,oracle:1521
传输协议:TCP/UDP
二、类 InetAddress
2.1、InetAddress 主机对象
IP 地址是 IP 使用的 32 位或 128 位无符号数字,它是一种低级协议,UDP 和 TCP 协议都是在它的基础上构建的
2.2、示例
import java.net.*; class IPDemo { public static void main(String[] args) throws Exception { //getLoaclHostAddress(); getAllByName(); } /* 获取本机的IP和主机名 */ public static void getLoaclHostAddress() throws Exception { //返回本地主机 InetAddress ia=InetAddress.getLocalHost(); System.out.println(ia.toString()); //主机名 String hostName=ia.getHostName(); //IP地址 String ip=ia.getHostAddress(); System.out.println("hostName="+hostName+".....ip="+ip); } /* 获取163或者百度的所有IP地址集合 */ public static void getAllByName() throws Exception { //获取淘宝的主机数组 InetAddress [] ia=InetAddress.getAllByName("www.163.com"); for(InetAddress i:ia) { //输出主机IP地址 System.out.println("IP:"+i.getHostAddress()); System.out.println("Name:"+i.getHostName()); } } }
三、TCP与UDP
3.1、概述
四、Socket
4.1、Socket
Socket就是为网络服务提供的一种机制
通信两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO通信
五、UDP
5.1、概述
此类表示用来发送和接收数据报包的套接字。
构造方法摘要 | |
---|---|
DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口。 |
|
protected
|
DatagramSocket(DatagramSocketImpl impl)
创建带有指定 DatagramSocketImpl 的未绑定数据报套接字。 |
DatagramSocket(int port)
创建数据报套接字并将其绑定到本地主机上的指定端口。 |
|
DatagramSocket(int port,
InetAddress laddr)
创建数据报套接字,将其绑定到指定的本地地址。 |
|
DatagramSocket(SocketAddress bindaddr)
创建数据报套接字,将其绑定到指定的本地套接字地址。 |
此类表示数据报包。
数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。
构造方法摘要 | |
---|---|
DatagramPacket(byte[] buf, int length) 构造 DatagramPacket ,用来接收长度为
length 的数据包。 |
|
DatagramPacket(byte[] buf,
int length, InetAddress address, int port)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。 |
|
DatagramPacket(byte[] buf,
int offset, int length) 构造 DatagramPacket ,用来接收长度为 length
的包,在缓冲区中指定了偏移量。 |
|
DatagramPacket(byte[] buf,
int offset, int length, InetAddress address, int port)
构造数据报包,用来将长度为 length 偏移量为 offset
的包发送到指定主机上的指定端口号。 |
|
DatagramPacket(byte[] buf,
int offset, int length, SocketAddress address)
构造数据报包,用来将长度为 length 偏移量为 offset
的包发送到指定主机上的指定端口号。 |
|
DatagramPacket(byte[] buf,
int length, SocketAddress address)
构造数据报包,用来将长度为 length
的包发送到指定主机上的指定端口号。 |
5.2、UDP发送端
/* 发送端 1.创建UDP服务,通过DatagramSocekt, 2.创建发送的数据,并封装为数据包,DatagramPacket 3.发送send 4.关闭DatagramSocekt资源 */ import java.net.*; class UdpSend { public static void main(String[] args) throws Exception { //1.创建UDP服务,通过DatagramSocekt, DatagramSocket ds=new DatagramSocket(); //2.创建发送的数据,并封装为数据包,DatagramPacket String say="udp数据!"; byte [] buf = say.getBytes(); InetAddress ia=InetAddress.getByName("localhost"); int port =9898; DatagramPacket dp=new DatagramPacket(buf,buf.length,ia,port); //3.发送send ds.send(dp); //4.关闭DatagramSocekt资源 ds.close(); } }
5.3、UDP接收端服务端
/* 接收端,服务端 1.创建UDP,Socket服务对象,DatagramSocket,设置商品 2.创建数据服包对象DatagramPacket包,接收数据报包 3.接收receive,到数据包在 4.通过数据报包,获取其中的数据如IP,数据和端口 5.解析数据转化为字符串,并打印 6.关闭资源 */ import java.net.*; class UdpReceive { public static void main(String[] args) throws Exception { //1.创建UDP,Socket服务对象,DatagramSocket,设置端口 DatagramSocket ds=new DatagramSocket(9898); //2.创建数据服包对象DatagramPacket包,接收数据报包 //接收内容的字节数据 byte[] buf=new byte[1024]; DatagramPacket dp=new DatagramPacket(buf,buf.length); //3.接收receive,到数据包在 ds.receive(dp); //4.通过数据报包,获取其中的数据如IP,数据和端口 //IPD String ip=dp.getAddress().getHostAddress(); //主机名 String hostname=dp.getAddress().getHostName(); //数据 String data=new String(dp.getData(),0,dp.getLength()); //5.解析数据转化为字符串,并打印 System.out.println(ip+":"+hostname+":"+data); //6.关闭资源 ds.close(); } }
5.4、键盘录入
/* 发送端 键盘录入 */ import java.net.*; import java.io.*; class UdpSend2 { public static void main(String[] args) throws Exception { //建立UDPSocket服务对象DatagramSocket DatagramSocket ds=new DatagramSocket(); //主机对象 InetAddress ia=InetAddress.getByName("localhost"); int port=10001; //录入数据,字符流,键盘录入 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String line=null; while((line=br.readLine())!=null) { if("886".equals(line)) break; //封装为数据报包 byte [] buf=line.getBytes(); DatagramPacket dp=new DatagramPacket(buf,buf.length,ia,port); //发送 ds.send(dp); } //关闭 br.close(); ds.close(); } }
/* 接收端一直开启 */ import java.net.*; class UdpRece2 { public static void main(String[] args) throws Exception { //建立DatagramSocket对象服务,并指定端口 DatagramSocket ds=new DatagramSocket(10001); while(true) { //接收数据报包 byte[] buf=new byte[1024]; DatagramPacket dp=new DatagramPacket(buf,buf.length); //接收 ds.receive(dp); //获取数据报中的数据 String ip=dp.getAddress().getHostAddress(); String data=new String(dp.getData(),0,dp.getLength()); System.out.println(ip+":"+data); } } }
5.5、示例
package com.pb.demo1; /* 简单聊天工具 */ //发送端 import java.net.*; import java.io.*; class Send implements Runnable { private DatagramSocket ds; public Send( DatagramSocket ds) { this.ds=ds; } //线程重写方法 public void run() { try {//接收键盘录入 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); InetAddress ia=InetAddress.getByName("192.168.2.255"); int port =10002; String line=null; while ((line=br.readLine())!=null) { if("886".equals(line)) break; //封装数据 byte[] buf=line.getBytes(); DatagramPacket dp=new DatagramPacket(buf,buf.length,ia,port); //发送 ds.send(dp); } } catch (Exception e) { throw new RuntimeException("发送失败!"); } } } //接收端 class Rece implements Runnable { private DatagramSocket ds; public Rece( DatagramSocket ds) { this.ds=ds; } //线程重写方法 public void run() { try { while (true) { //接收 byte[] buf=new byte[1024]; DatagramPacket dp=new DatagramPacket(buf,buf.length); ds.receive(dp); //通过数据报获取信息 String ip=dp.getAddress().getHostAddress(); String data=new String(dp.getData(),0,dp.getLength()); //输出 System.out.println(ip+":"+data); } } catch (Exception e) { throw new RuntimeException("接收失败!"); } } } class ChatDemo { public static void main(String[] args) throws Exception { //发送 DatagramSocket send=new DatagramSocket(); //接收 DatagramSocket rece=new DatagramSocket(10002); new Thread(new Send(send)).start(); new Thread(new Rece(rece)).start(); } }
六、TCP
5.1、概述
5.2、TCP传输一次-简单使用
/* TCP传输 1.TCP分客户端与服务端 2.客户端:Socket 服务端:ServerSocket */ /* 客户端: Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字 Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 Socket(InetAddress host, int port, boolean stream) 已过时。 Use DatagramSocket instead for UDP transport. Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程地址上的指定远程端口。 Socket(Proxy proxy) 创建一个未连接的套接字并指定代理类型(如果有),该代理不管其他设置如何都应被使用。 protected Socket(SocketImpl impl) 使用用户指定的 SocketImpl 创建一个未连接 Socket。 Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。 Socket(String host, int port, boolean stream) 已过时。 使用 DatagramSocket 取代 UDP 传输。 Socket(String host, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程主机上的指定远程端口。 通过构造方法可以发现: Socket对象,在建立时,就可以去连接指定主机 因为Tcp是面向连接的,所以在连接成功,形成通路后, 在该通道进行数据的传输 步骤: 1.创建客户端Socket服务,指定主机与端口 2.获取Socket流,socket.getXXX(InputStream或者OutputStream,并封装为字符流或者字节流 3.发送数据 4.关闭socket服务 */ import java.net.*; import java.io.*; class TcpClient { public static void main(String[] args) throws Exception { //1.创建客户端Socket服务,指定主机与端口 Socket s=new Socket("localhost",10003); //2.获取Socket流,socket.getXXX(InputStream或者OutputStream,并封装为字符流或者字节流 OutputStream os=s.getOutputStream(); //3.发送数据 String say="Tcp客户端发送,测试数据!"; os.write(say.getBytes()); //4.关闭socket服务 s.close(); } } /* 步骤: 1.创建服务端Socket服务,指定端口 2.监听accept,并获取Socket流,没有连接,这个方法是阻塞工的 3.获取对应客户端对象的socket.getXXX(InputStream或者OutputStream,并封装为字符流或者字节流 4.接收数据InptuStream或者发送OutputStream 5.打印 6.(可选一般不关闭)关闭socket服务 */ class TcpServer { public static void main(String[] args) throws Exception { //1.创建服务端Socket服务,指定端口 ServerSocket ss=new ServerSocket(10003); //2.监听accept,并获取Socket流,没有连接,这个方法是阻塞工的 Socket s=ss.accept(); //3.获取对应客户端对象的socket.getXXX(InputStream或者OutputStream,并封装为字符流或者字节流 //4.接收数据InptuStream或者发送OutputStream InputStream is=s.getInputStream(); //获取客户端IP String ip=s.getInetAddress().getHostAddress(); //设置缓冲区 byte[] buf=new byte[1024]; //把数据读取到缓冲区中 int len=is.read(buf); //转换为字符串 String data=new String(buf,0,len); //5.打印 System.out.println(ip+"........"); System.out.println(data); //6.(可选一般不关闭)关闭socket服务 s.close(); ss.close(); } }
5.3、SocetKet接收与返回
/* 客户端给服务端发送数据 服务端收到后给客户端反馈信息 客户接收反馈数据 */ /*步骤: 1.创建客户端Socket服务,指定主机与端口 2.获取Socket流,socket.getXXX(InputStream或者OutputStream,并封装为字符流或者字节流 3.发送数据 4.关闭socket服务 */ import java.net.*; import java.io.*; class TcpClient2 { public static void main(String[] args) throws Exception { //1.建立Socekt服务并指定端口 Socket s=new Socket("localhost",10004); //2.信息 String sendInfo="客户端发送的信息!"; //3.获取输出流写到服务端 OutputStream os=s.getOutputStream(); os.write(sendInfo.getBytes()); //4.获取输入信息接收服务端信息 InputStream is=s.getInputStream(); byte [] buf=new byte[1024]; int len=is.read(buf); String rev=new String(buf,0,len); System.out.println("服务端反馈的信息:"+rev); s.close(); } } /* 步骤: 1.创建服务端Socket服务,指定端口 2.监听accept,并获取Socket流,没有连接,这个方法是阻塞工的 3.获取对应客户端对象的socket.getXXX(InputStream或者OutputStream,并封装为字符流或者字节流 4.接收数据InptuStream或者发送OutputStream 5.打印 6.(可选一般不关闭)关闭socket服务 */ class TcpServer2 { public static void main(String[] args) throws Exception { //建立服务端ServerSocket数据 ServerSocket ss=new ServerSocket(10004); //获取客户端对象accept, Socket s=ss.accept(); //获取输入流对象接收客户端信息 InputStream is=s.getInputStream(); //建立缓冲区 byte [] buf=new byte[1024]; int len=is.read(buf); String clientInfo=new String(buf,0,len); //获取IP String ip=s.getInetAddress().getHostAddress(); System.out.println(ip+"....."+clientInfo); //返回给客户端的信息 String rel="已经收到了"; //获取输出流对象 OutputStream os=s.getOutputStream(); os.write(rel.getBytes()); //关闭 可选 s.close(); ss.close(); } }
5.4、综合
/* 建立一个转换服务器 客户端输入内容到服务器,服务把内容转成大写再返回给客户端 客户端可以 不断的进行文本输入, 当客户端输入over时结束 */ /* 客户端 操作设备上的数据,可以使用IO技术 并按照IO的操作规律来完成 源:键盘录入 目的:网络设置,网络输出 而且操作的是文本数据,可以选择 字符流与字符缓冲流 */ import java.io.*; import java.net.*; class TcpClient3 { public static void main(String[] args) throws Exception { //建立服务 Socket s=new Socket("localhost",10005); //获取键盘录入 BufferedReader br= new BufferedReader(new InputStreamReader(System.in)); //目的发送给服务端 //BufferedWriter bwOut=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); //打印流,可以接收字符流、缓冲流、字节流,第二个参数true表示自动刷新 PrintWriter out=new PrintWriter(s.getOutputStream(),true); //获取服务端返回的信息 BufferedReader brIn= new BufferedReader(new InputStreamReader(s.getInputStream())); //键盘录入数据 String line=null; //服务端返回数据 String recLine=null; //接收键盘录入 while((line=br.readLine())!=null) { if("over".equals(line)) break; out.println(line); /* //将信息写入服务端 bwOut.write(line); //增加换行 bwOut.newLine(); //刷新缓冲区 bwOut.flush(); */ //获取取服务端返回的大写数据 recLine=brIn.readLine(); System.out.println("服务器返回信息:"+recLine); } //结束,关资源 s.close(); } } /* 服务器 */ class TcpServer3 { public static void main(String[] args) throws Exception { //建立服务端对象 ServerSocket ss=new ServerSocket(10005); //获取客户端Socket对象 Socket s=ss.accept(); String ip=s.getInetAddress().getHostAddress(); System.out.println(ip+"...."); //获取客户端流对象 BufferedReader brIn= new BufferedReader(new InputStreamReader(s.getInputStream())); //BufferedWriter bwOut=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); //打印流,可以接收字符流也可以接收字节流,加true自动刷新 PrintWriter out=new PrintWriter(s.getOutputStream(),true); String line=null; while((line=brIn.readLine())!=null) { System.out.println("客户端说:"+line); out.println(line.toUpperCase()); /* //转换为大写返回客户端 bwOut.write(line.toUpperCase()); //增加换行 bwOut.newLine(); //刷新缓冲区 bwOut.flush(); */ } s.close(); ss.close(); } } /* 问题: 客户端和服务端都在莫名的等待 因为客户端和服务端都在阻塞的方法, 这些方法没有读到结束标记,那么就一直等待 而导致两端,都在等待 */
5.5、示例-TCP文件复制
/* 上传一个文件到服务器 */ import java.net.*; import java.io.*; /* 客户端 */ class UploadClient { public static void main(String[] args) throws Exception { //建立客户端服务 Socket s=new Socket("localhost",10009); //上传文件 File file=new File("d:\\gm.mp3"); //获取文件名 String filename=file.getName(); //建立基本数据流将文件名发送过去 PrintWriter pw=new PrintWriter(s.getOutputStream(),true); //发送 pw.println(filename); //建立输入流 FileInputStream fis=new FileInputStream(file); BufferedInputStream bis=new BufferedInputStream(fis); //建立流输出 BufferedOutputStream bos=new BufferedOutputStream(s.getOutputStream()); //建立字符缓冲,接收服务端返回的提示信息 BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream())); int len=0; while((len=bis.read())!=-1) { bos.write(len); bos.flush(); } //关闭输出流,增加结束标记 s.shutdownOutput(); String str=br.readLine(); System.out.println(str); bis.close(); fis.close(); s.close(); } } /* 服务端 */ class UploadServer { public static void main(String[] args) throws Exception { //建立服务 ServerSocket ss=new ServerSocket(10009); //获取客户端对象 Socket s=ss.accept(); //获取客户端 发送的文件名 BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream())); String filename=br.readLine(); System.out.println("文件名:"+filename); //文件输读流 BufferedInputStream bis=new BufferedInputStream(s.getInputStream()); //文件输出流 File f=new File("f:\\",filename); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(f)); //输出提示信息 PrintWriter pw=new PrintWriter(s.getOutputStream(),true); int len=0; while((len=bis.read())!=-1) { bos.write(len); bos.flush(); } pw.println("上传成功"); bos.close(); s.close(); ss.close(); } }