网络通信的关键三要素
IP、端口号、协议
IP地址
IP地址(Internet Protocol):全程“互联网协议地址”,是分配给上网设备的唯一标志。
IP地址有两种形式:IPv4、IPv6
InetAddress
代表IP地址
InetAddress 的常用方法如下
名称 | 说明 |
---|---|
public static InetAdress getLocalHost() | 获取本机IP,会以一个inetAddress 的对象返回 |
public static InetAddress getByName(String host) | 根据ip地址或者域名,返回一个inetAddress对象 |
public String getHostName() | 获取该IP地址对象对应的主机名。 |
public String getHostAddress() | 获取该IP地址对象中的ip地址信息 |
public boolean isReachable(int timeout) | 在指定毫秒内,判断主机与该ip对应主机是否能够联通 |
import java.net.InetAddress;
import java.sql.SQLOutput;public class InetAddresstest {public static void main (String[] args )throws Exception{//1、获取本机IP地址对象InetAddress ip1 = InetAddress.getLocalHost();System.out.println(ip1.getHostName());System.out.println(ip1.getHostAddress());//2、获取指定IP或者域名的IP地址对象InetAddress ip2=InetAddress.getByName("www.baidu.com");System.out.println(ip2.getHostName());System.out.println(ip2.getHostAddress());System.out.println(ip2.isReachable(6000));}}
端口号
标记正在设备上运行的应用程序的,被规定为一个16位的二进制,范围是0~65535
分类
周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用80,FTP占用21)
注册端口:1024~49151,分配给用户进程或某些应用程序。
动态端口:49151到65535,之所以被称为动态端口,是因为它一般不固定分配某种进程,而是动态分配。
注意:我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则会出错。
通信协议
网络上通信设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。
开放式互联网络互联标准:OSI 网络参考模型
OSI网络参考模型:全球网络互联标准
TCP/IP网络模型:事实上的国际标准
传输层的两个通信协议
UDP(User Datagram Protocol):用户数据报协议;
TCP(Transmission Control Protocol) :传输控制协议
UDP
特点:无连接、不可靠通信
不事先建立连接,数据按照包发,一包数据含:自己的IP、程序端口、目的IP、程序端口和数据(限制在64KB内)
发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,是不可靠的。
TCP
特点:面向连接、可靠通信。
TCP的最终目的:要保证在不可靠的信道上实现可靠传输。
TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接。
UDP通信
特点:无连接、不可靠通信
不事先建立连接;发送端每次要把发送的数据(限制在64KB内)、接收端IP、等信息封装成一个数据包,发不出去就算了。
Java提供了一个Java.net.DatagramSocket类来实现UDP通信。
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.sql.SQLOutput;public class Server {public static void main(String[] args) throws Exception{//1、创建一个服务对象(创建一个接韭菜的人)注册端口DatagramSocket socket =new DatagramSocket(6666);//2、创建一个数据包对象,用于接受数据的(创建一个韭菜盘子)byte[] buffer = new byte[1024*64];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);while (true) {//3、开始正式使用数据包来接受客户端发来的数据socket.receive(packet);//4、从字节数组中,把接收到的数据直接打印出来//接受多少就到处多少//获取本次数据包接受了多少数据。int len = packet.getLength();String rs= new String(buffer,0,len);System.out.println(rs);System.out.println(packet.getAddress().getHostAddress());System.out.println(packet.getPort());System.out.println("----------------");}}
}import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception{//1、创建客户端对象DatagramSocket socket = new DatagramSocket();//2、创建数据包对象封装要发出去的数据(创建一个韭菜盒子)//public DatagramPacket(byte buf[],int length,InetAddress address,int port)//InetAddress address,int port)//参数1:封装要发出去的数据。//参数2:发出去的数据大小(字节个数)//参数3:服务器额的IP地址//参数4:服务程序的端口Scanner sc= new Scanner(System.in);while (true) {System.out.println("请说:");String msg= sc.nextLine();if("exit".equals(msg)) {System.out.println("欢迎下次光临!推出成功!");socket.close();break;}byte[] bytes = msg.getBytes();DatagramPacket packet = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),6666);//3、正式发送这个数据包的数据出去了socket.send(packet);}}
}
TCP通信
特点:面向连接、可靠通信
通信方面事先会采用”方式建立可靠连接“,实现端到端的通信;底层能保证数据成功传给服务器
java提供了一个Java.net.Socket类来实现TCP通信。
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.SQLOutput;public class Server {public static void main(String[] args) throws Exception{//1、创建ServerSocket的对象,同时为服务端注册端口ServerSocket serverSocket = new ServerSocket(8888);//2、从serverSocket对象,调用accept方法,等待客户端的连接请求Socket socket = serverSocket.accept();//3、从socket通信管道中得到一个字节输入流InputStream is = socket.getInputStream();//4、把原始的字节输入流包装成数据输入流DataInputStream dis = new DataInputStream(is);//5、使用数据输入流读取客户端发过来的消息String rs=dis.readUTF();System.out.println(rs);//其实我们也可以获取客户端的IP地址System.out.println(socket.getRemoteSocketAddress());dis.close();socket.close();}
}import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception{//1、创建Socket对象,并同时请求与服务端程序的连接Socket socket= new Socket("127.0.0.1",8888);//2、从socket通信管道中得到一个字节输出流,用来发数据给服务端程序。OutputStream os= socket.getOutputStream();//3、把低级字节输出流包装成数据输出流DataOutputStream dos = new DataOutputStream(os);//4.开始写数据出去了dos.writeUTF("在一起号码!");dos.close();socket.close();}
}
下面是一个简单的Java程序,用于实现多个客户端同时通信:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;public class MultiClientServer {private List<Socket> clients = new ArrayList<>();public static void main(String[] args) {MultiClientServer server = new MultiClientServer();server.start();}public void start() {try {ServerSocket serverSocket = new ServerSocket(9999);System.out.println("Server started");while (true) {Socket clientSocket = serverSocket.accept();clients.add(clientSocket);ClientHandler clientHandler = new ClientHandler(clientSocket);Thread clientThread = new Thread(clientHandler);clientThread.start();}} catch (Exception e) {e.printStackTrace();}}private class ClientHandler implements Runnable {private Socket clientSocket;private BufferedReader reader;private PrintWriter writer;public ClientHandler(Socket clientSocket) {this.clientSocket = clientSocket;try {reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));writer = new PrintWriter(clientSocket.getOutputStream(), true);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void run() {try {String message;while ((message = reader.readLine()) != null) {System.out.println("Received message: " + message);// 向所有客户端发送消息for (Socket client : clients) {PrintWriter clientWriter = new PrintWriter(client.getOutputStream(), true);clientWriter.println(message);}}} catch (Exception e) {e.printStackTrace();}}}
}
这个程序创建了一个服务器端,可以同时处理多个客户端的连接。当一个客户端发送消息时,服务器会将该消息转发给所有连接的客户端。
运行这个程序后,可以使用多个客户端程序连接到服务器,并进行通信。每个客户端发送的消息都会被服务器广播给所有连接的客户端。
注意:这个程序是一个简单的示例,没有处理异常情况和并发安全性。在实际使用中,应该对异常进行处理并确保多个线程之间的安全访问。