p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解
目录
- 网络编程概念
- 网络编程三要素
- IP
- InetAddress类
- 端口号
- 协议
- UDP协议
- UDP通信程序(发送数据)
- UDP通信程序(发送数据)
- 使用UDP写聊天室项目
- UDP的通信方式
- TCP协议
- 通过TCP协议实现多发多收
- 通过TCP协议实现数据的接收与反馈
- 通过TCP协议上传文件
网络编程概念
网络编程,就是在网络通信协议下,不同计算机上运行的程序,进行的数据传输
其应用场景有很多:即时通信、网络对战、金融证券、国际贸易、邮件······
不管是什么场景,其本质都是计算机跟计算机之间通过网络进行数据传输
我们可以用java.net包下的技术来进行开发网络应用程序
常见的软件架构两种:CS、BS
CS:即Client/Server(客户端/服务器)。采取这种架构的软件在用户本地需要下载并安装客户端程序,在远程有一个服务器端程序
BS:即Browser/Server(浏览器/服务器)。采取这种架构的软件只需要一个浏览器,用户通过不同的网址。客户访问不同的服务器。
.
.
.
CS的优点:画面可以做得很精美,用户体验好
CS的缺点:需要开发客服端,也要开发服务器;用户需要下载和更新的时候太麻烦
.
BS的优点:不需要开发客户端,只需要页面+服务器;用户不需要下载,打开浏览器就能使用
BS的缺点:如果应用过大,用户体验会受到影响
网络编程三要素
- 确定对方电脑在互联网上的地址,即IP
- 确定接收数据的软件,即端口号
- 确定网络传输的规则,即协议
.
IP:设备在网络上的地址,是唯一标识
端口号:应用程序在设备中的唯一标识
协议:数据在网络上的传输的规则,常见的协议有UDP、TCP、http、https、ftp
IP
IP(Internet Protocol):即互联网协议地址,也叫IP地址,是分配给上网设备的数字标签
常见的ip分为ipv4、ipv6
ipv4(Internet Protocol version 4),即互联网通信协议第四版。其采用的是32位地址长度,分为4组
缺点:ip太少,不够使用
为了解决这一问题,于是便有了ipv6
ipv6(Internet Protocol version 6),即互联网通信协议第六版。其采用的是128位地址长度,分为8组
ipv4的地址分类形式:公网地址(万维网使用)和私有地址(局域网使用)
192.168.开头的就是私有地址,范围即为192.168.0.0—192.168.255,255,专门为组织机构内部使用,以此节省IP
特殊IP:127.0.0.1,也叫做localhost,是回送地址也称本地回环地址,也称为本机IP,永远只会寻找当前所在的本机
常用的CMD指令:
ipconfig:查看本机IP地址
ping:检查网络是否连通
InetAddress类
public static void main(String[] args) throws UnknownHostException {//获取InetAddress对象InetAddress address = InetAddress.getByName("LAPTOP-T3HRL7ID");//确定主机名称的IP地址,主机名称可以是机器名称,也可以是IP地址System.out.println(address);System.out.println(address.getHostName());//获取此IP地址的主机名System.out.println(address.getHostAddress());//返回文本显示中的IP地址字符串}
端口号
端口号是应用程序在设备中的唯一标识,一个端口号只能被一个应用程序所使用
端口号:由两个字节表示的整数,取值范围为0~65535
其中0~1023之间的端口号被用于一些知名的网络服务和应用
我们自己使用的端口号为1024以上
协议
UDP协议:用户数据报协议(User Datagram Protocol)
UDP是面向无连接通信协议
特点:速度快、有大小限制一次最多发送64K,数据不安全、容易丢失数据
应用场景:文件传输、邮件发送、网页浏览等需要高可靠性的数据传输。
TCP协议:传输控制协议(TransmissionControl Protocol)
TCP是一种面向连接的通信协议
速度慢、没有大小限制、数据安全
应用场景:视频会议、实时直播、在线游戏等允许少量数据丢失,但要求速度快的应用。
UDP协议
UDP通信程序(发送数据)
步骤:
- 创建发送端的DatagramSocket对象(比作找快递公司)
- 数据打包(DatagramPacket)(打包礼物)
- 发送数据(快递公司发包裹)
- 释放资源(付钱走人)
举例
import java.io.IOException;
import java.net.*;public class Demo2 {public static void main(String[] args) throws IOException {//1. 创建发送端的DatagramSocket对象//创建对象时要绑定端口,以后我们就是通过这个端口往外发送//空参:所有可用的端口中随机一个进行使用//有参:指定端口好进行绑定DatagramSocket ds = new DatagramSocket();//2. 数据打包String str = "你好世界!";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);//3. 发送数据ds.send(dp);//4. 释放资源ds.close();}
}
UDP通信程序(发送数据)
步骤:
- 创建接收端的DatagramSocket对象(比作找快递公司)
- 接收打包好的数据(接受箱子)
- 解析数据包(从箱子中获取礼物)
- 释放资源(签收走人)
举例
import java.io.IOException;
import java.net.*;public class Demo3 {public static void main(String[] args) throws IOException {//1. 创建接收端的DatagramSocket对象//创建对象时要绑定端口,以后我们就是通过这个端口接收数据//而且绑定的端口一定要与发送数据的端口保持一致//空参:所有可用的端口中随机一个进行使用//有参:指定端口好进行绑定DatagramSocket ds = new DatagramSocket(10086);//2. 接收打包好的数据byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);//程序到这一步的时候,会在这里死等//等发送端发来消息ds.receive(dp);//3. 解析数据包byte[] data = dp.getData();int length = dp.getLength();InetAddress address = dp.getAddress();int port = dp.getPort();System.out.println("接收到数据" + new String(data,0,length));System.out.println("数据从"+address+"这台电脑的"+port+"这个端口发出");//4. 释放资源ds.close();//运行的时候先运行接收端再运行发送端}
}
使用UDP写聊天室项目
发送端
import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class talkRoomSendMessage {public static void main(String[] args) throws IOException {//按下面要求实现程序//UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束//UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收//1. 创建发送端的DatagramSocket对象DatagramSocket ds = new DatagramSocket();//打包数据Scanner scanner = new Scanner(System.in);while (true) {System.out.println("输入要说的话");String str = scanner.nextLine();if ("886".equals(str)){break;}byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes, bytes.length,address,port);//发送数据ds.send(dp);}//释放资源ds.close();}
}
接收端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class talkRoomReceiveMessage {public static void main(String[] args) throws IOException {//按下面要求实现程序//UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束//UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收//1. 创建发送端的DatagramSocket对象DatagramSocket ds = new DatagramSocket(10086);//接收数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);while (true) {ds.receive(dp);//解析数据包byte[] data = dp.getData();int length = dp.getLength();String ip = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();System.out.println("ip为"+ip+",主机名为"+name+"的人,发送了数据:"+new String(data,0,length));}//运行的时候先运行接收端再运行发送端}
}
UDP的通信方式
UDP的通信方式有三种:单播、组播、广播
单播,即一对一,一台电脑只给一台电脑发送数据
组播,即一对多,一台电脑能给一组电脑发送数据。组播预留地址为224.0.0.0~224.0.0.255
广播,即一对多,一台电脑能给局域网中所有的电脑发送数据。广播地址为255.255.255.255
组播通信(发送端)
import java.io.IOException;
import java.net.*;public class Demo2 {public static void main(String[] args) throws IOException {//组播发送数据//1. 创建发送端的MulticastSocket对象//创建对象时要绑定端口,以后我们就是通过这个端口往外发送//空参:所有可用的端口中随机一个进行使用//有参:指定端口好进行绑定MulticastSocket ms = new MulticastSocket();//2. 数据打包String str = "你好世界!";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("224.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);//3. 发送数据ms.send(dp);//4. 释放资源ms.close();}
}
组播通信(接收端)
import java.io.IOException;
import java.net.*;public class Demo3 {public static void main(String[] args) throws IOException {//组播接收数据//1. 创建接收端的MulticastSocket对象//创建对象时要绑定端口,以后我们就是通过这个端口接收数据//而且绑定的端口一定要与发送数据的端口保持一致//空参:所有可用的端口中随机一个进行使用//有参:指定端口好进行绑定MulticastSocket ms = new MulticastSocket(10086);//将当前本机,添加到224.0.0.1的这一组当中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);//2. 接收打包好的数据byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);//程序到这一步的时候,会在这里死等//等发送端发来消息ms.receive(dp);//解析数据包byte[] data = dp.getData();int length = dp.getLength();String ip = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();System.out.println("ip为"+ip+",主机名为"+name+"的人,发送了数据:"+new String(data,0,length));//4. 释放资源ms.close();//运行的时候先运行接收端再运行发送端}
}
TCP协议
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象
通信之前要保证连接已经建立,之后会通过Socket产生IO流来进行网络通信
客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//TCP协议:发送数据//创建Socket对象//在创建对象的同时会连接服务端,如果连接不上(比如两个端口不一致),代码会报错Socket socket = new Socket("127.0.0.1",10086);//可以从连接通道中获取输出流OutputStream os = socket.getOutputStream();os.write("你好世界!".getBytes());//释放资源//由于IO流后于Socket通道创建,所以要先关闭IO流os.close();socket.close();}
}
服务器
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//TCP协议:接收数据//创建ServerSocket对象//两个端口要一致ServerSocket ss = new ServerSocket(10086);//监听客户端的连接Socket socket = ss.accept();//从连接通道中获取输入流读取数据InputStream is = socket.getInputStream();//通过转换流将字节流转换为字符流(防止出现中文乱码问题)InputStreamReader isr = new InputStreamReader(is);//通过使用缓冲字符流来提高效率BufferedReader br = new BufferedReader(isr);int b;while ((b = br.read()) != -1){System.out.print((char) b);}//释放资源//关闭连接通道socket.close();//关闭服务器ss.close();}
}
其中通道的建立以及断开是分别通过两个协议保证进行的,分别为三次握手和四次挥手
通过TCP协议实现多发多收
客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class TestClient {public static void main(String[] args) throws IOException {//客户端:多次发送数据//服务器:多次接收数据,并打印//创建Socket对象并连接服务器Socket socket = new Socket("127.0.0.1",10086);//写出数据Scanner scanner = new Scanner(System.in);while (true) {System.out.println("输入你要发送的信息");String str = scanner.nextLine();if ("886".equals(str)){break;}OutputStream os = socket.getOutputStream();os.write(str.getBytes());}//释放资源socket.close();}
}
服务器
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class TestServer {public static void main(String[] args) throws IOException {//客户端:多次发送数据//服务器:多次接收数据,并打印//创建对象,绑定10086端口ServerSocket ss = new ServerSocket(10086);//等待客户端连接Socket socket = ss.accept();//读取数据InputStreamReader isr = new InputStreamReader(socket.getInputStream());int b;while ((b = isr.read()) != -1){System.out.print((char) b);}//释放资源socket.close();ss.close();}
}
通过TCP协议实现数据的接收与反馈
客户端
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;public class Test2Client {public static void main(String[] args) throws IOException {//客户端:发送一条数据,接收服务端反馈的消息并打印//服务器:接收数据并打印,再给客户端反馈消息//创建Socket对象并连接服务器Socket socket = new Socket("127.0.0.1",10086);//写出数据String str = "你好世界!";OutputStream os = socket.getOutputStream();os.write(str.getBytes());//写出一个结束标记,防止服务端死循环接收socket.shutdownOutput();//获取服务端回写的数据//socket中获取输入流读取数据InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is);int b;while ((b = isr.read()) != -1){System.out.print((char)b );}//释放资源socket.close();}
}
服务端
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Test2Server {public static void main(String[] args) throws IOException {//客户端:发送一条数据,接收服务端反馈的消息并打印//服务器:接收数据并打印,再给客户端反馈消息//创建对象并绑定端口ServerSocket ss = new ServerSocket(10086);//等待客户端连接Socket socket = ss.accept();//socket中获取输入流读取数据InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is);int b;while ((b = isr.read()) != -1){System.out.print((char)b );}//回写数据String str = "反馈:服务器已收到";OutputStream os = socket.getOutputStream();os.write(str.getBytes());//释放资源socket.close();ss.close();}
}
通过TCP协议上传文件
客户端
package study.IP;import java.io.*;
import java.net.Socket;public class Test3Client {public static void main(String[] args) throws IOException {//客户端:将本地文件上传到服务器,接收服务器的反馈//服务器:接收客户端上传的文件,上传完毕之后给出反馈//创建Socket对象并连接服务器Socket socket = new Socket("127.0.0.1",10086);//读取本地文件中的数据,并写到服务器当中BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\a"));BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes))!= -1){bos.write(bytes,0,len);}//往服务器写出结束标记socket.shutdownOutput();//接收服务器的回写数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String line = br.readLine();System.out.println(line);//释放资源socket.close();}
}
服务端
package study.IP;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class Test3Server {public static void main(String[] args) throws IOException {//客户端:将本地文件上传到服务器,接收服务器的反馈//服务器:接收客户端上传的文件,上传完毕之后给出反馈//创建对象并绑定端口ServerSocket ss = new ServerSocket(10086);//等待客户端连接Socket socket = ss.accept();//读取数据并保存到本地文件中BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\aa"));byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes))!= -1){bos.write(bytes,0,len);}//回写数据BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上传成功");bw.newLine();bw.flush();//释放资源socket.close();ss.close();}
}