一、网络通信
概念:
1.两台设备之间通过网络实现数据传输
2.网络通信:将数据通过网络从一台设备传输到另一台设备
3. java.net包下提供了一系列的类或接口,供程序员使用,完成网络通信
ip地址:
域名和端口概念:
访问机制如图:在网络开发中,不要使用0-1024的端口
Tcp/ip:运用流程
网络通信协议:
TCP和UDP:
二、InetAddress
相关方法:
1.获取本机InetAddress对象getLocalHost
2.根据指定主机名/域名获取ip地址对象getByName
3.获取InetAddress对象的主机名getHostName
4.获取InetAddress对象的地址 getHostAddress
流程:
实际代码操作:
import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; public class API_ { public static void main(String[] args) throws UnknownHostException { //获取本机主机的名和ip InetAddress localHost = Inet4Address.getLocalHost();//DESKTOP-RHF15I8/192.168.19.1 System.out.println(localHost); //通过本机的主机名获取本地信息 InetAddress name = Inet4Address.getByName("DESKTOP-RHF15I8"); System.out.println(name);//DESKTOP-RHF15I8/192.168.19.1 //通过域名地址获取站点信息 InetAddress byName = Inet4Address.getByName("www.baidu.com"); System.out.println(byName);//www.baidu.com/14.215.177.39 //通过InetAddress对象获取对应的地址 String hostAddress = byName.getHostAddress();//182.61.200.6 System.out.println(hostAddress); //通过InetAddress对象获取对应的主机名(HostName:主机名,HostAddress:ip) String address = byName.getHostName();//www.baidu.com System.out.println(address); } }
三、TCP网络通信编程(socket)
基本介绍:
1.套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准。
2.通信的两端都要有Socket,是两台机器间通信的端点
3.网络通信其实就是Socket间的通信。
4.Socket允许程序把网络连接当成一个流,数据在两个Socket间通过I0传输。
5.一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
原理图解:(TCP编程可靠,UDP编程不可靠)
1、完成一个客户端和服务器的连接通信操作:
流程如下:
使用字节流主要代码
//服务器端 import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { //创建一个ServerSocket,监听本机的9999端口 //要确定该端口没有其他的服务在监听这个端口 //ServerSocket可以通过accept返回多个Socket,达到多用户连接效果 ServerSocket serverSocket = new ServerSocket(9999); //阻塞在此处等待客户机连接,客户机连接成功后会创建一个Socket套接字 Socket socket = serverSocket.accept(); System.out.println("有客户端连接到服务器!"); //创建一个输入流(输出流和输入流都可以通过Socket创建) InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); byte[] bytes = new byte[1024]; int line; //IO读取数据操作 while ((line = inputStream.read(bytes)) != -1) { System.out.println(new String(bytes,0,line)); } outputStream.write("hello,client!".getBytes()); socket.shutdownOutput(); //关闭一下接口服务 inputStream.close(); outputStream.close(); socket.close(); serverSocket.close(); } } //客户端 import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; public class Client { public static void main(String[] args) throws IOException { //创建一个Socket套接字,有客户主机和端口,才可以连接到对应的服务器 Socket socket = new Socket(InetAddress.getLocalHost(), 9999); //定义一个输出流/输入流 OutputStream outputStream = socket.getOutputStream(); InputStream inputStream = socket.getInputStream(); //输出到服务器端,注意输出流为字符流 outputStream.write("hello,server".getBytes()); socket.shutdownOutput(); byte[] bytes = new byte[1024]; int line; while ((line = inputStream.read(bytes)) != -1) { System.out.println(new String(bytes,0,line)); } //需要关闭相应的流和套接字 inputStream.close(); outputStream.close(); socket.close(); } }
使用字符流主要代码
//Server服务器端 @Test public void Server01() throws IOException { //创建一个ServerSocket,监听本机的9999端口 //要确定该端口没有其他的服务在监听这个端口 //ServerSocket可以通过accept返回多个Socket,达到多用户连接效果 ServerSocket serverSocket = new ServerSocket(9999); //阻塞在此处等待客户机连接,客户机连接成功后会创建一个Socket套接字 Socket socket = serverSocket.accept(); System.out.println("有客户端连接到服务器!"); //创建一个输入流(输出流和输入流都可以通过Socket创建) InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream)); //IO读取数据操作 System.out.println(reader.readLine()); writer.write("hello,client"); writer.newLine(); writer.flush(); //关闭一下接口服务 writer.close(); reader.close(); socket.close(); serverSocket.close(); } //Client客户端 @Test public void Client02() throws IOException { //创建一个Socket套接字,有客户主机和端口,才可以连接到对应的服务器 Socket socket = new Socket(InetAddress.getLocalHost(), 9999); //定义一个输出流/输入流 OutputStream outputStream = socket.getOutputStream(); InputStream inputStream = socket.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream)); //输出到服务器端,注意输出流为字节流 writer.write("hello Server!!"); // writer.newLine();//注意在使用这个时要放在 writer.flush();之前,不然不会起作用 writer.flush(); socket.shutdownOutput();//writer.newLine();也可以表示输出结束,但是对方要使用reader.readLine();才会知道输入已经结束 System.out.println(reader.readLine()); //需要关闭相应的流和套接字 writer.close(); reader.close(); socket.close(); }
2、网络文件传输
代码实例:
//服务器端 import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class TcpFileUpLoadServer { public static void main(String[] args) throws Exception { //监听接口 ServerSocket serverSocket = new ServerSocket(9999); //等待连接 Socket socket = serverSocket.accept(); //创建一个输入的管道 BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream()); //将得到的图片资源转换成一个byte[]数组 byte[] bytes = StreamUtils.streamToByteArray(inputStream); //将文件资源保存到本地 BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("src\\test22.jpg")); outputStream.write(bytes); outputStream.flush(); //给客户端返回自己已经收到的信息 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); writer.write("收到图片!"); writer.flush(); //关闭相关的流和管道 outputStream.close(); socket.close(); writer.close(); serverSocket.close(); } } //客户端 import java.io.*; import java.net.InetAddress; import java.net.Socket; public class TcpFileUpLoadClient { public static void main(String[] args) throws Exception { //图片地址 String imgPath = "C:\\Users\\wenman\\Desktop\\imageTest\\test11.jpg"; //连接服务器 Socket socket = new Socket(InetAddress.getLocalHost(), 9999); BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(imgPath)); //将图片文件转换为一个字节数组 byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream); //创建一个发送数据到服务器的管道流 BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream()); //将图片文件发送到管道 outputStream.write(bytes); outputStream.flush(); socket.shutdownOutput(); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println(reader.readLine()); //关闭相关资源 reader.close(); outputStream.close(); socket.close(); } } //引用的工具类 import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.InputStreamReader; /** * 此类用于演示关于流的读写方法 * */ public class StreamUtils { /** * 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[] * @param is * @return * @throws Exception */ public static byte[] streamToByteArray(InputStream is) throws Exception{ ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象 byte[] b = new byte[1024];//字节数组 int len; while((len=is.read(b))!=-1){//循环读取 bos.write(b, 0, len);//把读取到的数据,写入bos } byte[] array = bos.toByteArray();//然后将bos 转成字节数组 bos.close(); return array; } /** * 功能:将InputStream转换成String * @param is * @return * @throws Exception */ public static String streamToString(InputStream is) throws Exception{ BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder builder= new StringBuilder(); String line; while((line=reader.readLine())!=null){ builder.append(line+"\r\n"); } return builder.toString(); } }
3、netstat指令:
1). netstat -an可以查看当前主机网络情况,包括端口监听情况和网络连接情况
2). netstat -an | more可以分页显示
3).要求在dos控制台下执行
说明:
(1) Listening表示某个端口在监听
(2)如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息.
注意:当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这个端口是TCP/IP来分配的,是不确定的,是随机的.。
四、UDP网络通信编程
基本介绍:
1.类 DatagramSocket和 DatagramPacket实现了基于UDP 协议网络程序。
2.UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP
数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
3. DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和
端口号以及接收端的IP地址和端口号。
4.UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方
的连接
UDP说明:
1.没有明确的服务端和客户端,演变成数据的发送端和接收端
2.接收数据和发送数据是通过 DatagramSocket 对象完成
3.将数据封装到DatagramPacket 对象/装包
4.当接收到DatagramPacket 对象,需要进行拆包,取出数据
5. DatagramSocket可以指定在哪个端口接收数据
UDP传输编程实现:
//服务器端 import java.io.IOException; import java.net.*; public class UDPReceiver { public static void main(String[] args) throws IOException { //创建 DatagramSocket对象,准备在8888接收数据 DatagramSocket socket = new DatagramSocket(8888); //将需要发送的数据报封装到DatagramPacket,封装需要数据的字节数组,数组的长度,IP地址,以及对方的端口号 byte[] bytes = "hello,明天一起去潇洒!".getBytes(); DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.19.1"), 9999); //发送数据报 socket.send(packet); //接收数据报 byte[] bytes1 = new byte[1024]; DatagramPacket packet1 = new DatagramPacket(bytes1, bytes.length); socket.receive(packet1); byte[] data = packet1.getData(); System.out.println(new String(data,0,data.length)); socket.close(); } } //客户端 import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UDPSender { public static void main(String[] args) throws IOException { //1. 创建一个DatagramSocket对象,在端口9999准备接收数据 DatagramSocket socket = new DatagramSocket(9999); //2.创建一个DatagramPacket对象,用来保存接收到的数据 byte[] bytes = new byte[1024]; DatagramPacket packet = new DatagramPacket(bytes,bytes.length); //3.调用接收方法,将通过网络传输的DatagramPacket对象填充到packet对象 //当有数据包发送到这个端口时,就会把数据放入这个package中,如果没有发送到 //这个窗口就会一直堵塞 socket.receive(packet); //拆包packet.getData();返回一个byte[]对象 获取数据报的长度:int length = packet.getLength(); byte[] data = packet.getData(); System.out.println(new String(data,0, data.length)); byte[] bytes1 = "好的,明天见".getBytes(); DatagramPacket packet1 = new DatagramPacket(bytes1, bytes1.length, InetAddress.getByName("192.168.19.1"), 8888); socket.send(packet1); socket.close(); } }
一个项目的开发流程: