什么是网络编程
在网络通信协议下,不同计算机上运行的程序,进行的数据传输。
-
应用场景:即时通信、网游对战、金融证券、国际贸易、邮件等等。
不管是什么场景,都是计算机跟计算机之间通过网络进行数据传输。
-
Java中可以使用Java.net包下的技术轻松开发出常见的网络应用程序。
常见的软件架构:
BS:Browser/Server 浏览器/服务器
只需要一个浏览器,用户提供不同的网址。客户访问不同的服务器。
优缺点:
-
不需要开发客户端,只需要页面+服务端
-
用户不需要下载,打开浏览器就能使用
-
如果应用过大,用户体验受到影响
CS:Client/S2erver 客户端/服务器
在用户本地想要下载并安装客户端程序,在远程有一个服务器端程序。
优缺点:
服务器就不需要将图片、音乐等等资源发送给客户端,客户端已经下载,只需要告诉客户端该显示什么资源了。
-
画面可以做的非常精美,用户体验好
-
需要开发客户端、也需要开发服务端
-
用户需要下载和更新的时候太麻烦
网络编程三要素
IP(Internet Protocol)
是互联网协议地址,也称IP地址。分配给上网设备的数字标签
-
上网设备在网络中的地址,是唯一的标识
常见的IP分类为:IPv4、IPv6
IPv4:互联网通信协议第四版
目前主流
采用32位地址长度,分为4组
最多只有2的32次方个IP,目前以使用完
IPv4的地址分类形式
-
公网地址(万维网使用)和私有地址(局域网使用)
-
192.168.开头的就是私有地址,范围即为192.168.0.0--192.168.255.255,专门为组织机构内部使用,以此节省IP
特殊的IP地址
127.0.0.1,也可以是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。
IPv6:互联网通信协议第六版
解决IPv4不够用的问题
采用128位地址长度,分为8组,采用,冒分十六进制表示法
最多有2的128次方个IP,可以给地球上每个沙子一个IP。
常用的CMD命令
-
ipconfig:查看本机IP地址
-
ping:检查网络是否连通
InetAddress使用
此类表示互联网协议(IP)地址
没有构造方法,不能直接new,用静态方法getbyname
package com.cg;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class MyInetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
/*
* static InetAddress getByName(String host) 根据主机名确定主机的 IP 地址。 主机名可以是机器名称,也可以是IP地址
* String getHostAddress() 以文本形式返回 IP 地址字符串。
* String getHostName() 获取此 IP 地址的主机名。
* */
//1、获取InetAddress的对象
//address IP的对象 一台电脑的对象
InetAddress indexAddress = InetAddress.getByName("192.168.1.100");
System.out.println(indexAddress);
InetAddress address = InetAddress.getByName("薄荷");
System.out.println(address);
String name = address.getHostName();
System.out.println(name);//薄荷
String ip = address.getHostAddress();
System.out.println(ip); //192.168.140.1
}
}
——————————————————————————————————————————
/192.168.1.100
薄荷/192.168.140.1
薄荷
192.168.140.1
这是一个前置的代码,获取到某一台电脑对象之后,就可以给这台电脑发送信息
端口号
-
应用程序在设备中唯一的标识
端口号:由两个字节表示的整数,取值范围:0~65535
其中0~1023之间的端口号用于一些知名的网络服务或者应用。
我们自己使用1024以上的端口号就可以了。
注意:一个端口号只能被一个应用程序使用
协议
计算机网络中,连接和通信的规则被称为网络通信协议
-
数据在网络中传输的规则,常见的协议有:UDP、TCP、http、https、ftp。
-
OSI参考模型:世界互联协议标准,全国通信规范,单模型过于理想化,未能在因特网上进行广泛推广
-
TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
OSI参考模型 |
---|
应用层 |
表示层 |
会话层 |
传输层 |
网络层 |
数据链路层 |
物理层 |
例如:在自己电脑将一条信息一层一层的往下,在物理层将数据转换成二进制,然后传输给其他电脑的物理层在解析,一层一层的往上达到应用层。
太理想化,太复杂
TCP/IP参考模型 | TCP/IP参考模型各层对应协议 | 面向那些 |
---|---|---|
应用层 | HTTP、FTP、Telnet、DNS.... | 一般是应用程序需要关注的。如浏览器,邮箱。程序员一般在这一层开发。 |
传输层 | TCP、UDP、..... | 选择传输使用的TCP,UDP协议 |
网络层 | IP、ICMP、ARP、..... | 封装自己的IP,对方的IP等信息 |
物理(+数据)链路层 | 硬件设备。010100101010100101010..... | 转换成二进制利用物理设备传输 |
UDP协议
-
用户数据报协议(User DATagram Protocol)
-
UDP是面向无连接通信协议。
速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据
不管设备是否已经连接成功
都会发送消息,能收到就收到,收不到就算了
应用场景
网络会议、语音通话、在线视频
发送数据
-
创建发送端的DATagramSocket对象
-
数据打包(DatagramPacket)
-
发送数据
-
释放资源
package com.cg;
import java.io.IOException;
import java.net.*;
public class SendMessageDemo {
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 datagramPacket = new DatagramPacket(bytes,bytes.length,address,port);
//3、发送数据
ds.send(datagramPacket);
//4、释放资源
ds.close();
}
}
接收数据
-
创建接收端的DatagramSocket对象
-
接收打包好的数据
-
解析数据包
-
释放资源
package com.cg;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class ReceiveMessageDemo {
public static void main(String[] args) throws IOException {
//接收数据
//1、创建DATagramSocket对象 (快递公司)
//细节:
//在接收的时候一定要绑定端口
//而且绑定的端口一定要和发送的端口保持一致
DatagramSocket ds = new DatagramSocket(10086);
//2、接收数据包
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
//该方法是阻塞的
//程序执行到这一步的时候,会在这里死等
//等发送端发送消息
ds.receive(datagramPacket);
//3、解析数据包
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
InetAddress address = datagramPacket.getAddress();
int port = datagramPacket.getPort();
System.out.println("接收到数据"+new String(data,0,length));
System.out.println("该数据是从"+address+"这台电脑中的"+port+"这个端口号发出的");
//4、释放资源
ds.close();
}
}
——————————————————————————————————————————————————————————————————————————
接收到数据你好呀微
该数据是从/127.0.0.1这台电脑中的63035这个端口号发出的
-
按照下面的要求实现程序
-
UDP发送数据: 数据来自于键盘录入,直到输入的数据是886,发送数据结束
-
UDP接收数据: 因为接收端不知道发送端什么时候停止发送,故采用死循环接收
-
package com.cg;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class SendMessageDemo {
public static void main(String[] args) throws IOException {
//1、创建DATagramSocket对象
DatagramSocket ds = new DatagramSocket();
//2、打包数据
Scanner scan = new Scanner(System.in);
while (true) { //ctrl+alt+T
System.out.println("请输入您要说的话:");
String str = scan.nextLine();
if ("886".equals(str)){
break;
}
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
//改为255.255.255.255 在发送的时候就可以给局域网里所有的电脑发送
int port = 10086;
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,address,port);
//3、发送数据
ds.send(datagramPacket);
}
//4、释放资源
ds.close();
}
}
package com.cg;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveMessageDemo {
public static void main(String[] args) throws IOException {
//1、创建DATagramSocket对象
DatagramSocket ds = new DatagramSocket(10086);
//2、接收数据包
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
while (true) {
ds.receive(datagramPacket);
//3、解析数据包
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String ip = datagramPacket.getAddress().getHostAddress();
String name = datagramPacket.getAddress().getHostName();
//4、打印数据
System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
}
}
}
实现多个发送端发送消息:
点击 Edit Configurations.....
选中发送端程序 点击 Modify options
选择 Allow multiple instances
三种通信方式
单播
一对一
之前写的代码就是单播
组播
一台电脑可以给一组电脑发送数据
组播地址:224.0.0.0~239.255.255.255
其中224.0.0.0~224.0.0.255为预留的组播地址
代码实现
package com.cg.demo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class SendMessageDemo {
public static void main(String[] args) throws IOException {
/*
* 组播发送端代码
* */
//创建MulticastSocket对象
MulticastSocket multicastSocket = new MulticastSocket();
//创建DatagramPacket对象
String str = "你好,你好";
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("224.0.0.1");
int port = 10000;
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,address,port);
//发送数据
multicastSocket.send(datagramPacket);
//释放资源
multicastSocket.close();
}
}
package com.cg.demo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class ReceiveMessageDemo1 {
public static void main(String[] args) throws IOException {
/*
* 组播接收端代码
* */
//1、创建MulticastSocket对象
MulticastSocket multicastSocket = new MulticastSocket(10000);
//2、将当前本机,添加到224.0.0.1的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.1");
multicastSocket.joinGroup(address);
//3、创建DatagramPacket 数据包对象
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
//4、接收数据
multicastSocket.receive(datagramPacket);
//5、解析数据
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String ip = datagramPacket.getAddress().getHostAddress();
String name = datagramPacket.getAddress().getHostName();
System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
//6、释放资源
multicastSocket.close();
}
}
package com.cg.demo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class ReceiveMessageDemo2 {
public static void main(String[] args) throws IOException {
/*
* 组播接收端代码
* */
//1、创建MulticastSocket对象
MulticastSocket multicastSocket = new MulticastSocket(10000);
//2、将当前本机,添加到224.0.0.1的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.1");
multicastSocket.joinGroup(address);
//3、创建DatagramPacket 数据包对象
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
//4、接收数据
multicastSocket.receive(datagramPacket);
//5、解析数据
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String ip = datagramPacket.getAddress().getHostAddress();
String name = datagramPacket.getAddress().getHostName();
System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
//6、释放资源
multicastSocket.close();
}
}
package com.cg.demo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class ReceiveMessageDemo3 {
public static void main(String[] args) throws IOException {
/*
* 组播接收端代码
* */
//1、创建MulticastSocket对象
MulticastSocket multicastSocket = new MulticastSocket(10000);
//2、将当前本机,添加到224.0.0.1的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.1");
multicastSocket.joinGroup(address);
//3、创建DatagramPacket 数据包对象
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
//4、接收数据
multicastSocket.receive(datagramPacket);
//5、解析数据
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String ip = datagramPacket.getAddress().getHostAddress();
String name = datagramPacket.getAddress().getHostName();
System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
//6、释放资源
multicastSocket.close();
}
}
广播
一台电脑可以给局域网中所有的电脑发送数据
广播地址:255.255.255.255
代码实现
package com.cg;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class SendMessageDemo {
public static void main(String[] args) throws IOException {
//1、创建DATagramSocket对象
DatagramSocket ds = new DatagramSocket();
//2、打包数据
Scanner scan = new Scanner(System.in);
while (true) { //ctrl+alt+T
System.out.println("请输入您要说的话:");
String str = scan.nextLine();
if ("886".equals(str)){
break;
}
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("255.255.255.255");
//改为255.255.255.255 在发送的时候就可以给局域网里所有的电脑发送
int port = 10086;
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,address,port);
//3、发送数据
ds.send(datagramPacket);
}
//4、释放资源
ds.close();
}
}
package com.cg;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveMessageDemo {
public static void main(String[] args) throws IOException {
//1、创建DATagramSocket对象
DatagramSocket ds = new DatagramSocket(10086);
//2、接收数据包
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
while (true) {
ds.receive(datagramPacket);
//3、解析数据包
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String ip = datagramPacket.getAddress().getHostAddress();
String name = datagramPacket.getAddress().getHostName();
//4、打印数据
System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
}
}
}
TCP协议
-
传输控制协议TCP(Transmission Control Protocol)
-
TCP协议是面向连通的通信协议
速度慢,没有大小限制,数据安全
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象
通信前确保连接成功,才会发送数据
通过Socket产生的IO流来进行网络通信
应用场景
下载软件,文字聊天,发送邮件
实现
客户端(Socket)
-
创建客户端的Socket对象(Socket)与指定服务端连接
Socket(String host,int port)
-
获取输出流,写数据
OutputStream getOutputStream()
-
释放资源
void close()
package com.cg.demo2;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
//TCP协议,发送数据
//1、创建Socket对象
//细节:在创建对象的同时会连接服务器
// 如果连接不上,代码会报错
Socket socket = new Socket("127.0.0.1",10086);
//2、可以从连接通道中获取输出流
OutputStream os = socket.getOutputStream();
//写出数据
os.write("你好你好".getBytes());
//3、释放资源
os.close();
socket.close();
}
}
服务器(ServerSocket)
-
创建服务器的Socket对象(ServerSocket)
ServerSocket(int port) (端口号与客户端保持一致)
-
监听客户端连接,返回一个Socket对象
Socket accept()
-
获取输入流,读数据,并把数据显示在控制台
InputStream getInputStream()
-
释放资源
void close()
package com.cg.demo2;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//TCP协议 接收数据
//1、创建ServerSocket对象
ServerSocket serverSocket = new ServerSocket(10086);
//2、监听客户端的连接
Socket socket = serverSocket.accept();
//3、从连接通道中获取输入流读取数据
InputStream inputStream = socket.getInputStream();
int b;
while ((b = inputStream.read()) != -1){
System.out.println((char) b);
}
//4、释放资源
socket.close();
serverSocket.close();
}
}
___________________________________________________________
传中文会乱码
ä
½
å
¥
½
ä
½
å
¥
½
中文乱码问题
产生乱码原因:
没有指定编码表,会使用平台,默认的编码表 UTF-8
修改服务端
package com.cg.demo2;
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协议 接收数据
//1、创建ServerSocket对象
ServerSocket serverSocket = new ServerSocket(10086);
//2、监听客户端的连接
Socket socket = serverSocket.accept();
//3、从连接通道中获取输入流读取数据
// InputStream inputStream = socket.getInputStream();//字节流 一个字节一个字节的读
// //转换流 转换为字符流
// InputStreamReader reader = new InputStreamReader(inputStream);
// //想提高读取的效率 缓冲流
// BufferedReader bufferedReader = new BufferedReader(reader);
//更简单
BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(socket.getInputStream()));
int b;
while ((b = bufferedReader.read()) != -1){
System.out.print((char) b);
}
//4、释放资源
socket.close();
serverSocket.close();
}
}
三次握手
协议保证连接建立
客户端 ———客户端向服务器发送连接请求 等待服务器确认 ———>服务器
客户端 <———服务器向客户端返回一个响应 告诉客户端收到请求 ———服务端
客户端 ———客户端向服务器再次发出确认信息 连接建立 ———>服务端
四次挥手
利用这个协议断开连接
而且保证连接通道里面的数据已经处理完毕了
确保连接断开,且数据处理完毕
客户端 ——— 客户端向服务器发出取消连接请求 ———>服务器
客户端 <——— 服务器向客户端返回一个响应 表示收到客户端取消请求 ———服务器
|
服务器将最后的数据处理完毕
|
客户端 <——— 服务器向客户端发出确认取消信息 ———服务器
客户端 ——— 客户端再次发送确认消息 连接取消 ———>服务器