网络编程
1.在网络通信协议下,不同 计算机上运行的程序,进行的数据传输。
2.应用场景:即时通信、网游对战、金融证券、国际贸易、邮件等等。
3.Java中可以使用java.net包下的技术开发出常见的网络应用程序。
4.常见的软件架构有CS和BS两种:
- CS(Client/Server,客户端/服务器)
用户需要在本地下载并安装客户端程序,在远程有一个服务器端程序。
优点:画面可以做的非常精美,用户体验好
缺点:
1)需要开发客户端,也需要开发服务端
2)用户需要下载和更新比较麻烦
适合定制专业化的办公类软件,比如:IDEA、网游
-
BS(Browser/Server,浏览器/服务器)
只需要一个浏览器,用户通过不同的网址,客户访问不同的服务器。
优点:
1)不需要开发客户端,只需要页面 + 服务端
2)用户不需要下载,打开浏览器就能使用
缺点:如果应用过大,用户体验会受到影响(因为实时传输数据,画质等会受影响)
适合移动互联网应用,可以在任何地方随时访问的系统
5.网络编程三要素:
- 确定电脑在互联网上的地址:IP,IP是设备在网络中的地址,是唯一的标识
- 确定接收数据的软件:端口号,端口号是应用程序在设备中唯一的标识
- 确定网络传输的规则:协议,协议是数据在网络中传输的规则,常见的协议有UPP、TCP、http、https、ftp
IP
1.IP全程Internet Protocol,是互联网协议地址,也称IP地址。是分配给上网设备的数字标签。通俗理解就是上网设备在网络中的地址,是唯一的。
2.常见的IP分类为:
- IPv4:全称:Internet Protocol version 4,互联网通信协议第四版
1)采用32位地址长度(4字节),分为4组,每组长度为0-255,总共数量为2^32,但是仍然存在不够用的问题
2)采用点分十进制表示法,比如192.168.1.16
IPv4的地址分类形式:
1)公网地址(万维网使用)和私有地址(局域网使用)。
2)192.168.开头的就是私有地址,范围即为192.168.0.0 - 192.168.255.255,专门为组织机构内部使用,以此节省IP
特殊IP地址:
127.0.0.1,也可以是localhost:是会送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。
因为发送数据时,会先往路由器发送,然后路由器根据给出的IP地址再传到对应的IP地址处,即使是发送到的IP地址是本机的IP地址,而使用127.0.0.1去发送,就可以不经过路由器,在发送时网卡识别了,直接就传到本机
- IPv6:全称:Internet Protocol version 6,互联网通信协议第六版
1)为了解决IPv4不够用而出现的,提供了更多的IP地址,采用了128位地址长度,分成8组,每组的长度为0-2^16 - 1,总共数量为2^128。
2)采用冒分十六进制表示法,比如2001:0DB8:0000:0023:0008:0800:200C:417A,还可以省略每组的前面的0:2001:DB8:0:23:8:800:200C:417A
3)特殊情况:如果计算出的16进制表示形式中间有多个连续的0,可以使用0为压缩表示法,就是将连续的0省略不写,比如:FF01:0:0:0:0:0:0:1101 -> FF01::1101
3.常见的与IP相关的CMD命令:
- ipconfig:查看本机IP地址
- ping IP地址/网址(其实是网址对应的服务器IP):检查当前主机与对应IP的设备网络是否连通
4.与IP相关的类InetAddress:
- 有两个子类Inet4Address和Inet6Address,InetAddress会根据本机使用的是IPv4还是使用IPv6去创建对应的对象
- 只能通过InetAddress的静态方法getByName(String host)去创建InetAddress对象,不能直接new,String host可以传本机的IP地址或者主机名。主机名可打开此电脑,右键属性去查看计算机名
- 创建的InetAddress是IP的对象,可以直接看作是一台电脑的对象
- 相关方法
方法名 | 说明 |
String getHostName() | 获取主机名 |
String getHostAddress() | 获取主机对应的IP地址 |
端口号
1.应用程序再设备中唯一的标识,因此一个端口号只能被一个应用程序使用。
2.由两个字节表示的整数,取值范围:0~65535。其中0~1023之间的端口号用于一些知名的网络服务或者应用,一般自己使用的是1024以上的端口号。
协议
1.计算机网络中,连接和通信的规则被称为网络通信协议。
2.OSI参考模型:世界互联协议标准,全球通信规范,但模型过于理想化,未能再因特网上进行广泛推广。
3.TCP/IP参考模型(或TCP/IP协议):对OSI中应用层表示层会话层进行了合并,数据链路层和物理层进行了合并,事实上的国际标准。
4.UDP协议:
- 用户数据报协议(User Datagram Protocol)
- UDP是无连接、不可靠的通信协议,速度快,有大小限制,以此最多发送64K,数据不安全,易丢失数据
- 无连接就是不检查设备之间是否连通就直接发送,只管发送,不管能不能收到
- 适用场景:网络会议、语音通话、在线视频(能接受丢失部分数据的场景)
5.TCP协议:
- 传输控制协议TCP(Transmission Cotrol Protocol)
- TCP协议是面向连接的通信协议,速度慢,没有大小限制,数据安全
- 适用场景:下载软件、文字聊天、发送邮件(不能丢失一点数据的场景)
UDP协议发送数据
以寄快递为例,步骤为四步:
1.找快递公司 ----- 创建发送端的DataGramSocket对象
2.打包礼物 ----- 数据打包(DatagramPacket)
3.快递公司发送包裹 ----- 发送数据
4.付钱走人 ----- 释放资源
// 1.找快递公司(创建发送端的DataGramSocket对象)
// 细节:
// 绑定端口,通过这个端口往外发送
// 空参:所有可用的端口中随机一个进行使用
// 有参:指定端口号进行绑定
DatagramSocket ds = new DatagramSocket();
// 2.打包数据
String str = "check check check";
// 因为在数据打包的时候,创建的DatagramPacket对象需要传入的是
// 字节数组,起始索引(可省略),传入数据长度,IP,端口号,因此先把这几个给先准备好
byte[] datas = str.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10000;
DatagramPacket dp = new DatagramPacket(datas,datas.length,address,port);
// 3.发送数据
ds.send(dp);
// 4.释放资源
ds.close();
UDP协议接收数据
以接收快递为例
1.找快递公司 ----- 创建接收端的DatagramSocket对象
2.接收箱子 ----- 接收打包好的数据
3.从箱子里面获取礼物 ----- 解析数据包
4.签收走人 ----- 释放资源
需要注意的是这里需要先启动接收数据程序,再启动发送数据程序,因为UDP发送数据是只负责发送,不查看是否连通设备,而先启动接收数据程序可以保证先连通,receive方法在接收到数据前会一直等待。
// 1.创建DatagramSocket对象(快递公司)
// 细节:
// 在接受的时候,一定要绑定端口
// 而且绑定的端口是跟发送时绑定的端口一致
DatagramSocket ds = new DatagramSocket(10000);
// 2.接收数据包
// 因为数据传输过来时的数据使用byte数组传输过来,接收时也是用byte数组接收
// byte数组的长度一定要大于传输过来数组长度,否则丢失数据
byte[] bytes = new byte[1024];
// 因为这里是接收数据,因此只需要把接受的长度以及接收的数组传过去即可
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
ds.receive(dp);
// 3.解析数据包
byte[] data = dp.getData(); // 获取数据包中的有数据部分
int len = dp.getLength(); // 获取数据包中的数据部分长度
InetAddress address = dp.getAddress(); // 获取发送的设备的IP地址
int port = dp.getPort(); // 获取发送的设备发送时使用的端口号
System.out.println("接收到数据" + new String(data,0,len));
System.out.println("该数据是从" + address + "这台电脑中的" + port + "端口发出的");
// 4.释放资源
ds.close();
UDP的三种通信方式
三种方式的区别就是在(找快递公司时)创建对象时的对象不同。
1.单播,一对一通讯。创建的是DatagramSocket对象。
2.组播,一对一组通讯。组播地址:224.0.0.0~239.255.255.255,其中224.0.0.0~224.0.0.255为预留的组播地址,一般只用这个范围内的组播地址。如果对组播地址中的任意一个地址发送信息,则在局域网中的处于组播地址中的所有电脑都能接收到该信息。创建的是MulticastSocket对象,如果想要当前主机也在组播地址内,可以先创建一个以224.0.0.1为形参的InetAddress对象address,再使用ms(ms为MuticastSocket实现类)的方法,ms.joinGroup(address)即可将本机添加到组播地址。
3.广播,一对所有通讯。广播地址:255.255.255.255,如果对广播地址发送信息,则在局域网中的所有电脑都会收到该信息
TCP通信程序
1.TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,通信之前要保证连接已经建立,通过Socket产生IO流来进行网络通信。
2.通信过程(客户端Socket发送数据):
- 创建客户端的Socket对象(Socket)与指定服务端连接 Socket(String host,int port)
- 获取输出流,写数据 OutputStream getOutputStream()
- 释放资源 void close()
// 1.创建客户端的Socket对象,参数中是连接的服务器的IP和对应端口
Socket socket = new Socket("127.0.0.1",10000);
// 2.获取输出流,写数据
OutputStream os = socket.getOutputStream();
Scanner sc = new Scanner(System.in);
String str;
while(true){
str = sc.nextLine();
os.write(str.getBytes());
if("886".equals(str)){
break;
}
}
// 3.释放资源
socket.close();
3.通信过程(服务器端ServerSocket接收数据):
- 创建服务器端的Socket对象(ServerSocket) ServerSocket(int port) ,这个port一定要去客户端的发送到的指定端口相同
- 监听客户端连接,返回一个Socket对象 Socket accept()
- 获取输入流,读数据,并把数据显示在控制台 InputStream getInputStream(),如果发送的是中文的数据,需要使用转换流将字节流转换为字符流再去读数据,否则容易乱码,如果想要使用缓冲流中的读取一行的方法,也可以进一步提升为缓冲流
- 释放资源 void close();释放资源时只要把通道关闭,输入流就自动关上了,因为输入流是通过Socket的实现类对象获取的,因此释放掉Socket资源就会同时释放输入流,客服端的输出流也是同理
// 1.创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(10000);
// 2.监听客户端连接,返回一个Socket对象
Socket socket = ss.accept();
// 3.获取输入流,读取数据
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
int b;
while ((b = isr.read()) != -1) {
System.out.print((char) b);
}
// 4.释放资源
socket.close();
ss.close();
4.在运行代码时要先运行服务端,因为先运行客户端时会发现没有服务端与其相连,就会报错,先运行服务端就会等待连接,不会报错。
5.在服务器端使用输入流读取数据时,判断流是否已经读完能否看读到最后会返回-1?
答:返回-1取决于处理的流的源头是什么,如果是文件流,这种想法或许是对的,因为文件流的大小是固定的,持续的读,总会读到文件的末尾(EOF),它总会返回-1的。但是,如果是网络流,例如TcpSocket,这样的流是没有末尾(EOF)的,如果你想读到-1,或许在远端被关闭了,而你还在读取,还是有可能读到-1的。实际情况是:网络连接状况很复杂,很有可能远端没有正常关闭而是进程死掉了,而是连接的线路断掉了,或者任何一个原因导致连接的通路无法正常传输数据。因此,如果连接没有断开,或者没有其他的原因导致传输异常,输入流会一直等输出流的数据,当使用Socket.shutdownOutpu()t或者异常情况出现的时候,使用输入流的read就会读取到-1。shutdownOutput方法相当于一个结束标记。
这里采用另一位博主的回答,我把相关的内容概括了一下。
https://blog.youkuaiyun.com/myling0626/article/details/50413268
TCP中的三次握手和四次挥手协议
1.三次握手:确保连接建立。服务端收到请求后不会马上建立连接,而是等客户端再次发出确认信息才会建立连接。
2.四次挥手协议:确保连接断开,保证连接通道里面的数据已经处理完毕了。
UUID
1.当上传文件时,文件名一般不能写定,最好使用一个每次都不一样的变量去命名,这个时候就可以使用UUID里面的randomUUID方法。
2.randomUUID方法是静态的,返回一个UUID类对象,使用其toString方法获取对应字符串,最后将格式转换一下即可。(不转换格式的输出类似c7322330-a405-4caa-9e2d-233b4fd3b3cb)
String name = UUID.randomUUID().toString.replaceAll("-");