二、网络通信三要素
互联网上的设备要进行通信,有三个要素。
- IP:
是设备在网络中的唯一标识,也就是说,一个IP就有唯一的一台设备,根据IP,就可以找到唯一的一台设备。
找到了设备,知道了要跟谁通信了,那么要跟这台设备上的哪个程序进程通信呢?那么就需要根据端口来判断。
- 端口:
用来区分设备上运行的不同的进程。有效端口为 0 ~ 65535 ,其中 0 ~ 1024 是系统保留的端口。
根据IP + 端口,我们可以找到需要进行通信的设备和该设备上对应的进程,按道理此时就可以进行通信了,实际上不是这样的。比如你是说中文的,你找到的那台设备的那个进程只能识别英文,那么语言就不互通了。这时候就需要用到协议。
- 协议:
可以简单的理解协议就是通信规则。让不同设备进行通信时可以语言互通。常用的协议有TCP协议和UDP协议。
TCP | UDP |
建立数据通道,可进行大量数据传输,效率较低,但安全可靠。 | 无需建立连接,使用数据包传递数据,每个数据包大小限制在64k,效率高,不可靠。 |
三、Java对网络编程的支持
Java对网络编程提供了良好的支持,其相关的类都在 java.net 包下。
- InetAddress类:
这个类可以理解为就是表示IP。
- 套接字:
套接字 = IP + 端口 。通信的两端(客户端和服务端) 都需要有套接字,套接字之间利用IO进行数据传输。客户端和服务端使用的套接字不同,TCP和UDP使用的套接字也不同。如下表。
方式 | 客户端 | 服务端 |
TCP | Socket | ServerSocket |
UDP | DatagramSocket、DatagramPacket | DatagramSocket、DatagramPacket |
四、Java网络编程小案例
1、使用UDP协议进行通信:
客户端(发送端)编程步骤:
- 创建发送端的socket对象;
- 创建数据,并把数据打包;
- 调用socket的发送方法发送数据;
- 释放资源。
public static void main(String[] args) throws Exception { //1.创建发送端的socket对象 DatagramSocket socket = new DatagramSocket(); //2.封装键盘录入的数据 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line = null; while ((line = br.readLine()) != null){ if ("886".equals(line))//如果输入886就停止服务 break; //3.创建数据,并把数据打包 byte[] bys = line.getBytes();//创建数据 int length = bys.length; InetAddress address = InetAddress.getByName("xxx.xxx.x.xxx");//IP int port = 10086;//端口 DatagramPacket dp = new DatagramPacket(bys,length,address,port);//打包数据 //4.调用socket的发送方法发送数据 socket.send(dp); } //5.释放资源 socket.close(); }
服务端(接收端)编程步骤:
- 创建接收端的socket对象;
- 创建数据包,用来接收数据;
- 调用socket对象的接收方法接收数据;
- 解析数据。
public static void main(String[] args) throws Exception { //1.创建接收端的socket对象 DatagramSocket ds = new DatagramSocket(10086); while (true){ //2.创建一个数据包(接收容器) byte[] bys = new byte[1024]; DatagramPacket dp = new DatagramPacket(bys,bys.length); //3.调用socket对象的接收方法接收数据 ds.receive(dp);//阻塞式方法 //4.解析数据包,显示在控制台 String s = new String(dp.getData(),0,dp.getLength()); System.out.println(dp.getAddress().getHostAddress()+":"+s); } }
其实这样就是一个简易的聊天室了,先开启服务端,然后开启客户端,在控制台用键盘录入数据,这些数据就会在服务端的控制台显示出来。我们可以用多线程改进一下,以达到启动一个main方法,又可以发送又可以接收的效果。代码如下:
public class SendThread implements Runnable{ private DatagramSocket ds; public SendThread(DatagramSocket ds) { this.ds = ds; } @Override public void run() { try { //2.封装键盘录入的数据 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line = null; while ((line = br.readLine()) != null){ if ("886".equals(line)) break; //3.创建数据,并把数据打包 DatagramPacket dp = new DatagramPacket( line.getBytes(), line.getBytes().length, InetAddress.getByName("xxx.xxx.x.xxx"), 12306); //4.调用socket的发送方法发送数据 ds.send(dp); } //5.释放资源 ds.close(); }catch (IOException e){ e.printStackTrace(); } }
public class ReceiveThread implements Runnable { private DatagramSocket ds; public ReceiveThread(DatagramSocket ds) { this.ds = ds; } @Override public void run() { try { while (true){ //2.创建一个数据包(接收容器) byte[] bys = new byte[1024]; DatagramPacket dp = new DatagramPacket(bys,bys.length); //3.调用socket对象的接收方法接收数据 ds.receive(dp);//阻塞式方法 //4.解析数据包,显示在控制台 String s = new String(dp.getData(),0,dp.getLength()); System.out.println(dp.getAddress().getHostAddress()+":"+s); } }catch (IOException e){ e.printStackTrace(); } } }
public class chatRoom { public static void main(String[] args) throws Exception { DatagramSocket send = new DatagramSocket(); DatagramSocket receive = new DatagramSocket(12306); SendThread st = new SendThread(send); ReceiveThread rt = new ReceiveThread(receive); Thread t1 = new Thread(st); Thread t2 = new Thread(rt); t1.start(); t2.start(); } }
以上就是通过多线程改进的简易的聊天室。
2、使用TCP协议进行通信:
客户端编程步骤:
- 创建发送端的socket对象;
- 获取输出流写数据;
- 释放资源。
public static void main(String[] args) throws Exception { //1.创建发送端的socket对象 Socket socket = new Socket("xxx.xxx.x.xxx",2222); //2.获取输出流写数据 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String line = null; while ((line = br.readLine()) != null){ if ("886".equals(line)) break; bw.write(line); bw.newLine(); bw.flush(); } //3.释放资源 socket.close(); }
服务端编程步骤:
- 创建接收端的socket对象;
- 监听客户端连接;
- 获取输入流读取数据;
- 释放资源。
public static void main(String[] args) throws IOException { //1.创建接收端的socket对象 ServerSocket serverSocket = new ServerSocket(2222); //2.监听客户端连接 Socket socket = serverSocket.accept(); //3.获取输入流读取数据,输出到文本文件 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt")); String line = null; while ((line = br.readLine()) != null){ bw.write(line); bw.newLine(); bw.flush(); } //4.释放资源 bw.close(); socket.close(); }
总结:
- 网络编程三要素就是IP、端口、协议。
- 协议主要是UDP和TCP两种。不管使用何种协议,客户端和服务端都需要有socket对象。
- UDP协议是将数据打包,每个数据包大小限制为64k,不建立连接,传输数据不可靠,但效率高。
- TCP协议会建立连接通道,传输的数据大小无限制,安全可靠,但效率较低。