一.网络相关基本概念
1.网络通信协议:是一种网络通用语言,为连接不同操作系统和不同硬件体系结构的互联网络引提供通信支持,是一种网络通用语言.通信协议的具体种类有很多,主要有:UDP协议和T CP协议
2.UDP 协议:是 User Datagram Protocol 的简称, 中文名是‘用户数据报协议‘.是一种无连接的协议。传输效率很高;数据不安全,容易丢失;
特点:
1:面向无连接;
2:效率高;
3:不安全;
3.TCP/IP 协议:Transmission Control Protocol/Internet Protocol 的简写,中译名为‘传输控制协议/因特网互联协议‘;
特点:
1:面向连接;(客户端和服务器需要事先建立起连接,才能通信,3次握手)
2:效率低;
3:数据安全;
4.网络协议数据传输流程:从下至上:链路层--网络层--传输层--应用层
链路层:软件驱动与硬件接口;
网络层:数据的分组与处理,IP 地址,端口号;
传输层:网络通信协议的核心,数据通过网络进行传输;
应用层:应用级软件,主要进行数据的解析;
5.IP 地址:是网络中的参与者的唯一身份标识.包含 IPV4/IPV6. IPV4 使用4个字节表示IP地址;每个字节的范围只能是 0-255 之间.
6.端口号:是电脑中用于识别不同进程;用2个字节表示一个端口号,能表示的范围 0-65535(2^16=65536);其中 0-1024 端口号已经被计算机的核心服务占用了,建议程序员使用1024之后
的端口号.
二.InetAddress 类(java.net)
介绍:InetAddress是java编写的一个类,用于描述计算机的ip地址;
构造方法:InetAddress构造方法不能直接使用,因此必须通过静态方法,获取对象:
继承关系:java.lang.Object--java.net.InetAddress
定义:public class InetAddress extends Object implements Serializable
静态方法:
public static InetAddress getByName(String host){}:在给定主机名的情况下确定主机的 IP 地址
public static InetAddress getLocalHost() throws UnknownHostException{}:返回本地主机
常用方法:
public String getHostAddress(){}:返回 IP 地址字符串(以文本表现形式)
public String getHostName(){}:获取此 IP 地址的主机名
代码演示:
1 import java.net.InetAddress; 2 import java.net.UnknownHostException; 3 public class NetDemo{ 4 public static void main(String[] args){ 5 //获取本地主机,返回InetAddress对象 6 InetAddress host = null; 7 try{ 8 host = InetAddress.getLocalHost(); 9 }catch(UnknownHostException e){ 10 e.printStackTrace(); 11 } 12 System.out.println(host); 13 14 //获取本地主机名 15 String name = host.getHostName(); 16 //获取本地ip 17 String ip = host.getHostAddress(); 18 System.out.println("计算机名:"+name+";ip为:"+ip); 19 20 //通过别人的计算机名,获取别人计算机的IP 21 try{ 22 host = InetAddress.getByName("LWL"); 23 }catch(UnknownHostException e){ 24 e.printStackTrace(); 25 } 26 String ip1 = host.getHostAddress(); 27 System.out.println(ip1); 28 } 29 }
二.UDP 常用类
1.DatagramPacket 类(java.net)
继承关系:java.lang.Object--java.net.DatagramPacket
定义:public final class DatagramPacket extends Object
构造方法:
DatagramPacket(byte[] buf, int length, InetAddress address, int port):构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
Buf:数组,用于保存要发送的数据;
Length:要发送的数据的长度;
Address:接收者的ip地址对象;
Port:接收者的端口号;
(这个对象用在发送端).
DatagramPacket(byte[] buf, int length):构造 DatagramPacket,用来接收长度为 length 的数据包。
Buf:发送者发送的数据将会保存到buf数组中;
Length:表示这个DatagramPacket对象的数组,有多少个位置可以使用;
(这个对象用在接收端).
常用主法:
public byte[] getData(){}:Returns the data buffer. The data received or the data to be sent starts from the offset in the buffer, and runs for length
long.
public int getLength(){}: Returns the length of the data to be sent or the length of the data received.
2.DatagramSocket 类(java.net)
继承关系:java.lang.Object--java.net.DatagramSocket
定义:public class DatagramSocket extends Object implements Closeable
构造方法:
DatagramSocket() throws SocketException:构造数据报套接字并将其绑定到本地主机上任何可用的端口。
(一般将该对象用在发送端,可以通过该对象,将数据报包对象发送出去)
DatagramSocket(int port) : 创建数据报套接字并将其绑定到本地主机上的指定端口。(一般用在接收端,监听指定的端口号,可以接收别人向该端口发送的数据报包)
常用方法:
public void send(DatagramPacket p) throws IOException{}:从此套接字发送数据报包
public void receive(DatagramPacket p) throws IOException{}:从此套接字接收数据报包。
该方法有线程阻塞的效果,因此必须在接收端先调用该方法,发送端才能发数据报包,否则会丢失数据报包
3.UDP通信案例
1 //UDP通信实现:Receiver 2 import java.net.DatagramPacket; 3 import java.net.DatagramSocket; 4 5 public class UDPReceiver { 6 public static void main(String[] args) throws Exception { 7 // 准备用于接收的数据报包对象 8 byte[] b = new byte[1024]; 9 DatagramPacket dp = new DatagramPacket(b, b.length); 10 // 创建接收端对象 11 DatagramSocket ds = new DatagramSocket(8891); 12 // 接收端使用自己的数据报包对象接收发送过来的数据 13 ds.receive(dp); 14 // 获取数组和有效长度 15 byte[] bs = dp.getData(); 16 int i = dp.getLength(); 17 // 转字符串 18 String s = new String(bs, 0, i); 19 System.out.println("发送端说:" + s); 20 ds.close(); 21 } 22 }
1 //UDP通信实现:sender 2 import java.net.DatagramPacket; 3 import java.net.DatagramSocket; 4 import java.net.InetAddress; 5 import java.util.Scanner; 6 7 public class UDPSender { 8 public static void main(String[] args) throws Exception { 9 // 提示发送者输入发送消息 10 Scanner sc = new Scanner(System.in); 11 System.out.println("请输入要发送的消息::"); 12 String message = sc.next(); 13 14 // 将输入的消息转化成字节数组 15 byte[] b = message.getBytes(); 16 // 将原始数据封装成DatagramPacket对象 17 DatagramPacket dp = new DatagramPacket(b, b.length, InetAddress.getLocalHost(), 8891); 18 // 创建发送端对象 19 DatagramSocket ds = new DatagramSocket(); 20 // 使用发送端对象将封装的DatagramPacket对象发送出去 21 ds.send(dp); 22 // 关闭流 23 ds.close(); 24 } 25 }
三.TCP 常用类
1.Socket
介绍:用于表示客户端的一个类.TCP 协议中客户端和服务器的交互是通过IO流完成的,而所有的 IO 流对象都是客户端提供的!
继承关系:java.lang.Object--java.net.Socket
定义:public class Socket extends Object implements Closeable
构造方法:
Socket(String host, int port) throws UnknownHostException,IOException :创建一个流套接字并将其连接到指定主机上的指定端口号。如果该客户端对象能创建成功,说明3次握手已经成功了!
2.ServerSocket
介绍:用于表示服务端的一个类
继承关系:java.lang.Object--java.net.ServerSocket
定义:public class ServerSocket extends Object implements Closeable
构造方法:
ServerSocket(int port) throws IOException : 创建绑定到特定端口的服务器套接字。实际开发中先有服务器对象,才会有客户端去访问;因此创建服务器对象的人,可以自己指定一个端口号;
常用方法:
public Socket accept() throws IOException{}: 侦听并接受到此套接字的连接。该方法有线程阻塞的效果,如果没有客户端访问该服务器,那么该服务器的当前线程将一直阻塞
3.TCP 通信案例
1 //客户端 2 import java.io.IOException; 3 import java.io.OutputStream; 4 import java.net.Socket; 5 import java.net.UnknownHostException; 6 import java.util.Scanner; 7 8 public class TCPClientDemo { 9 public static void main(String[] args) throws UnknownHostException, 10 IOException { 11 // 创建客户端对象 12 Socket s = new Socket("127.0.0.1", 9999); 13 // 面对客户端对象获取网络中的输出流 14 OutputStream out = s.getOutputStream(); 15 // 向网络中写入数据 16 Scanner sc = new Scanner(System.in); 17 System.out.println("请输入要发送的消息:"); 18 String str = sc.next(); 19 20 out.write(str.getBytes()); 21 } 22 }
1 //服务器端 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 public class TCPReceiverDemo { 8 public static void main(String[] args) throws IOException { 9 // 创建服务器端对象 10 ServerSocket ss = new ServerSocket(9999); 11 12 // 让服务器端对象等待客户端连接 accept 13 Socket s = ss.accept(); 14 15 // 面向Socket对象,获取输入流对象 16 InputStream in = s.getInputStream(); 17 18 // 一次读完 19 byte[] b = new byte[1024]; 20 int i = in.read(b); 21 22 // 转换成字符串输出 23 String str = new String(b, 0, i); 24 System.out.println("客户端发来消息:" + str); 25 } 26 }
4.文件上传案例--多线程版
1 /* 2 文件上传服务器端 多线程 3 */ 4 import java.io.FileOutputStream; 5 import java.io.InputStream; 6 import java.io.OutputStream; 7 import java.net.ServerSocket; 8 import java.net.Socket; 9 public class FileloadServer { 10 public static void main(String[] args) throws Exception { 11 // 创建服务器端对象 12 ServerSocket ss = new ServerSocket(8870); // throws IOException 13 // 监听端口,形成阻塞状态 14 while (true) { 15 final Socket s = ss.accept();// throws IOException 16 new Thread() { 17 @Override 18 public void run() { 19 try { 20 // 我是服务器中的程序,我要创建一个本地网络输入流 21 InputStream in = s.getInputStream(); 22 // 我是服务器中的程序,我要将网络输入流中的内容写入本地磁盘(位置如何确定?) 23 FileOutputStream fout = new FileOutputStream(System.currentTimeMillis() + ".jpg"); 24 int i = -1; 25 byte[] b = new byte[1024]; 26 while ((i = in.read(b)) != -1) { 27 fout.write(b, 0, i); // 写入本地磁盘 28 } 29 // 通知客户端上传成功,建立网络输出流 30 OutputStream out = s.getOutputStream(); 31 out.write("上传成功".getBytes()); 32 } catch (Exception e) { 33 e.printStackTrace(); 34 } 35 } 36 }.start(); 37 } 38 } 39 }
1 /* 2 上传文件客户端 3 */ 4 import java.io.FileInputStream; 5 import java.io.InputStream; 6 import java.io.OutputStream; 7 import java.net.Socket; 8 public class FileUploadClient { 9 public static void main(String[] args) throws Exception { 10 // 创建客户端对象 11 Socket s = new Socket("127.0.0.1", 8870);// throws UnknownHostException,IOException 12 // 创建本地文件的输入流 我是程序,我现在读取本地文件,创建字节输入流 13 FileInputStream fin = new FileInputStream("E:\\JAVAPractice\\net\\1.jpg");// throws FileNotFoundException 14 // 面向客户端 获取输出流,向网络中写入 15 OutputStream out = s.getOutputStream(); // throws IOException 16 // 循环 写入网络 17 int i = -1; 18 byte[] b = new byte[1024]; 19 while ((i = fin.read(b)) != -1) { 20 out.write(b, 0, i); 21 } 22 // 通知服务器端循环输出完成--解决死锁问题 23 s.shutdownOutput(); // throws IOException 24 // 若文件上传完成,服务器要通知我,我要接收这个消息,因此创建网络输入流,并打印在控制台上 25 InputStream in = s.getInputStream();// throws IOException 26 i = in.read(b); 27 String message = new String(b, 0, i);// Throws IndexOutOfBoundsException 28 System.out.println("消息来自服务端:" + message); 29 } 30 }