Java基础进阶_day17_(网络编程)
1. 网络编程
1.1 网络编程三要素
网络编程三要素:
A:IP地址
B:端口
C:协议
IP地址:
网络中计算机的唯一标识。
计算机只能识别二进制的数据,所以我们的IP地址应该是一个二进制的数据。
但是呢,我们配置的IP地址确不是二进制的,为什么呢?
IP:192.168.1.100
换算:11000000 10101000 00000001 01100100
假如真是:11000000 10101000 00000001 01100100的话。
我们如果每次再上课的时候要配置该IP地址,记忆起来就比较的麻烦。
所以,为了方便表示IP地址,我们就把IP地址的每一个字节上的数据换算成十进制,然后用.分开来表示:
"点分十进制"
IP地址的组成:网络号段+主机号段
A类:第一号段为网络号段+后三段的主机号段
一个网络号:256*256*256 = 16777216
B类:前二号段为网络号段+后二段的主机号段
一个网络号:256*256 = 65536
C类:前三号段为网络号段+后一段的主机号段
一个网络号:256
IP地址的分类:
A类 1.0.0.1---127.255.255.254 (1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址) (2)127.X.X.X是保留地址,用做循环测试用的。
B类 128.0.0.1---191.255.255.254 172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
C类 192.0.0.1---223.255.255.254 192.168.X.X是私有地址
D类 224.0.0.1---239.255.255.254
E类 240.0.0.1---247.255.255.254
两个DOS命令:
ipconfig 查看本机ip地址
ping 后面跟ip地址。测试本机与指定的ip地址间的通信是否有问题
特殊的IP地址:
127.0.0.1 回环地址(表示本机)
x.x.x.255 广播地址
x.x.x.0 网络地址
端口号:
正在运行的程序的标识。
有效端口:0~65535,其中0~1024系统使用或保留端口。
协议:
通信的规则
UDP:
把数据打包
数据有限制
不建立连接
速度快
不可靠
TCP:
建立连接通道
数据无限制
速度慢
可靠
举例:
UDP:发短信
TCP:打电话
1.2 UDP通信编程
* UDP通信:
* 将数据源和目的封装成数据包中,不需要建立连接;
* 每个数据报的大小在限制在64k;
* 因无连接,是不可靠协议;
* 不需要建立连接,速度快.
* Socket套接字:
* 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字.
* Socket原理机制:
* 通信的两端都有Socket;
* 网络通信其实就是Socket间的通信;
* 数据在两个Socket间通过IO传输.
* UDP通信的步骤:
* A:创建DatagramSocket与DatagramPacket类
* B:建立发送端,接收端;
* C:建立数据包;
* D:调用Socket的发送接收方法;
* E:关闭Socket;
* F:发送端与接收端是两个独立的运行程序.
* DatagramSocket类:此类表示用来发送和接收数据报包的套接字.
案例代码
/*
* 使用线程,不断发送数据
*/
public class SendData {
public static void main(String[] args) throws IOException,
UnknownHostException {
// 创建发送端对象,绑定到本地的12310端口,不指定端口时,默认使用的本机上可用的端口号
final DatagramSocket ds = new DatagramSocket(12311);
// 创建发送数据包
byte[] bys = new byte[1024];
// 设定发送到对方的数据,长度,地址,IP地址,端口
final DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getLocalHost(), 12309);
new Thread() {
@Override
public void run() {
// 设置数据并发送
Scanner sc = new Scanner(System.in);
while(true) {
String line = sc.nextLine();
if(line.equals("somnus")) {
break;
}
dp.setData(line.getBytes());
try {
ds.send(dp);
} catch (IOException e) {
e.printStackTrace();
}finally {
// 释放资源
// ds.close();
}
}
}
}.start();
}
}
/*
* 使用线程,不断接收数据
*/
public class ReceiveData {
public static void main(String[] args) throws IOException {
// 创建接收端套接字,绑定到本地的12309端口上
final DatagramSocket ds = new DatagramSocket(12309);
// 创建接收数据的套接字
byte[] bys = new byte[1024];
final DatagramPacket dp = new DatagramPacket(bys, bys.length);
// 接收数据并输出
new Thread() {
@Override
public void run() {
try {
while(true) {
ds.receive(dp);
System.out.println(dp.getAddress().getHostAddress()+":"+new String(dp.getData(), 0, dp.getLength()));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// 释放资源
ds.close();
}
}
}.start();
}
}
1.3 TCP通信编程
* TCP通信:
* 建立连接,形成传输数据的通道;
* 在连接中进行大数据量传输;
* 通过三次握手完成连接,是可靠协议;
* 必须建立连接,效率会稍低.
* TCP通信步骤:
* A:创建Socket客户端和ServerSocket服务端对象;
* B:建立客户端和服务器端;
* C:建立连接后,通过Socket中的IO流进行数据的传输;
* D:关闭socket;
* E:同样,客户端与服务器端是两个独立的应用程序.
案例代码
/*
* 将文件上传到服务器,客户端
*/
public class UpCilent {
public static void main(String[] args) throws IOException {
// 获取文件路径
File file = getFile();
// 将文件名上传到服务器进行校验是否存在
Socket client = new Socket("127.0.0.1", 12306);
// 创建输出流对象
BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream());
// 向服务器发送文件名
String fileName = file.getName();
bos.write(fileName.getBytes());
// 将缓冲区的数据刷出
bos.flush();
// 创建输入流对象
BufferedInputStream bis = new BufferedInputStream(client.getInputStream());
// 获取服务器对文件名校验的结果
byte[] bys = new byte[1024];
int len = bis.read(bys);
String result = new String(bys, 0, len);
if("存在".equals(result)) {
System.out.println("您要上传的文件已经存在,不能重复上传!");
client.close();
return;
}
// 文件不存在,则上传
BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file));
while((len = bis2.read(bys)) != -1) {
bos.write(bys, 0, len);
bos.flush();
}
// 释放资源
bis2.close();
client.close();
}
public static File getFile() {
// 定义键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个文件的路径名:");
while(true) {
File file = new File(sc.nextLine());
if(!file.exists()) {
System.out.println("您输入的文件路径不存在,请重新输入:");
} else if(file.isDirectory()) {
System.out.println("您输入的是文件夹路径,请输入文件路径:");
} else {
return file;
}
}
}
}
/*
* 上传文件到服务器,服务器端
*/
public class FileServer {
public static void main(String[] args) throws IOException {
// 创建服务器socket对象
ServerSocket server = new ServerSocket(12306);
// 创建存储接收客户端文件的文件夹
final File update = new File("update");
if(! update.exists()) {
update.mkdir();
}
// 持续接收客户端连接
while(true) {
final Socket s = server.accept();
// 创建线程接收客户端连接
new Thread() {
public void run() {
try {
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
byte[] bys = new byte[1024];
int len = bis.read(bys);
String fileName = new String(bys, 0, len);
File file = new File(update, fileName);
if(file.exists()) {
bos.write("存在".getBytes());
bos.flush();
// 文件存在,结束程序
s.close();
return;
} else {
// 文件不存在则返回标识
bos.write("不存在".getBytes());
bos.flush();
}
// 如果文件不存在,则上传
BufferedOutputStream bos2 = new BufferedOutputStream(new FileOutputStream(file));
while((len = bis.read(bys)) != -1) {
bos2.write(bys, 0, len);
bos2.flush();
}
// 释放资源
bos2.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}