网络编程
网络编程概述
网络
计算机网络:计算机网络系统就是利用通信设备和线路将地理位置不同、功能独立的多个计算机系统互
联起来,以功能完善的网络软件实现网络中资源共享和信息传递的系统
网络三要素
1.ip地址:标识计算机,是计算机在互联网上的唯一标识地址。
2.端口号:标识计算机上的软件的。不同的软件有不同的端口号,端口号 2个字节,0~65535 一般建
议使用8000之后。
mysql 3306 tomcat 8080
3.通信协议:双方应该遵循的规则。
HTTP:超文本传输协议
FTP: 文件传输协议
TCP/IP:传输控制协议/网际协议
UDP:用户数据包协议
网络的分层架构
IP地址
IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。标识计算机在互联网上的唯一地址。
格式:
ipV4:点分十进制,32位,由4个部分组成。例如: 192.168.0.1
ipV6:冒分十六进行,128位,例如:x:x:x 一个IPv6地址中间可能包含很长的一段0,可以把连续的一段0压缩为“::”
IP地址的分类: ABC DE特殊地址
(***)组播地址 D类IP地址在历史上被叫做多播地址(multicast address),即组播地址 224.0.0.0
到239.255.255.255
()广播地址 255.255.255.255 ()
本地回环地址 127.0.0.1 域名 localhost
java提供的ip地址
InetAddress
1.常用方法:
① getByName(String host) 根据参数获取InetAdress对象
② getHostName() 获取IP地址中域名的字符串形式
③ getHostAddress() 获取ip地址的字符串形式
④ getAllByName(String host)获取ip地址的数组
⑤ getLocalHost() 返回本机的ip地址
⑥ toString() 将ip地址转换为字符串。
代码
package com.demo;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
1.常用方法:
① getByName(String host) 根据参数获取InetAdress对象
② getHostName() 获取IP地址中域名的字符串形式
③ getHostAddress() 获取ip地址的字符串形式
④ getAllByName(String host)获取ip地址的数组
⑤ getLocalHost() 返回本机的ip地址
⑥ toString() 将ip地址转换为字符串。
*/
public class IP地址 {
public static void main(String[] args) throws UnknownHostException {
/*InetAddress ip = InetAddress.getByName("www.baidu.com");
System.out.println(ip.getHostName());
System.out.println(ip.getHostAddress());*/
// ④ getAllByName(String host)获取ip地址的数组
/* InetAddress[] ips = InetAddress.getAllByName("www.baidu.com");
for (InetAddress ip : ips) {
System.out.println(ip);
}*/
// ⑤ getLocalHost() 返回本机的ip地址
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1);
InetAddress ip2 = InetAddress.getByName("localhost");
System.out.println(ip2);
}
}
UDP
概念
UDP:传输层协议。用户数据包协议(UDP,User Datagram Protocol)。
无连接的传输协议。
特点:
无连接、不可靠、快速传输。数据报包进行传输,包最大不会超过64k
使用场景:
实时直播,视频,网游。
java中提供的UDP协议的类
DatagramSocket:发送端/接收端:此类表示用来发送和接收数据报包的套接字
DatagramPacket:表示数据报包。实现无连接包投递服务
发送端
发送端步骤
1.发送端:
① 发送端端点对象:
DatagramSocket()
② 打包数据
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
③ 发送
send(DatagramPacket p)
④ 关闭资源
close()
代码
package com.udpdemo;
import java.io.IOException;
import java.net.*;
/**
1.发送端:
① 发送端端点对象:
DatagramSocket()
② 打包数据
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
③ 发送
send(DatagramPacket p)
④ 关闭资源
close()
*/
public class 发送端 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
byte[] bt = "你好".getBytes();
DatagramPacket dp = new DatagramPacket(bt,bt.length, InetAddress.getByName("localhost"),9000);
ds.send(dp);
//接收
byte[] bt1= new byte[1024];
DatagramPacket dp1 = new DatagramPacket(bt1,bt1.length);
ds.receive(dp1);
System.out.println("发送端接收到的数据"+new String(dp1.getData(),0,dp1.getLength()));
ds.close();
}
}
接收端
① 接收端端点对象:DatagramSocket(int port)
② 接收数据报包,先创建空数据报包 然后接收数据。
DatagramPacket(byte[] buf, int length)
③ 接收:
receive(DatagramPacket p)
④ 关闭资源
close()
3.DatagramPacket常用方法:
① getLength() 获取数据报包中读取的数据的字节长度。
② getAddress() 接收端获取的发送端的ip地址
③ getPort() 接收端获取的发送端的端口号
代码
package com.udpdemo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
2.接收端:
① 接收端端点对象:DatagramSocket(int port)
② 接收数据报包,先创建空数据报包 然后接收数据。
DatagramPacket(byte[] buf, int length)
③ 接收:
receive(DatagramPacket p)
④ 关闭资源
close()
3.DatagramPacket常用方法:
① getLength() 获取数据报包中读取的数据的字节长度。
② getAddress() 接收端获取的发送端的ip地址
③ getPort() 接收端获取的发送端的端口号
*/
public class 接收端 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(9000);
byte[] bt = new byte[1024];
//数据报包的创建 空白
DatagramPacket dp = new DatagramPacket(bt,bt.length);
//接收
ds.receive(dp);
System.out.println(new String(bt,0,dp.getLength()));
//发送
byte[] bt1 = "发送端你好".getBytes();
//打数据报包
DatagramPacket dp1 = new DatagramPacket(bt1, bt1.length,dp.getAddress(),dp.getPort());
//接收端向发送端发送数据。
ds.send(dp1);
ds.close();
}
}
简易聊天室
发送端代码
package com.demo;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class 发送端 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入您要发送到接收端的数据:");
String msg = sc.nextLine();
byte[] bt = msg.getBytes();
//打数据报包
DatagramPacket dp = new DatagramPacket(bt, bt.length, InetAddress.getLocalHost(),9000);
//发送
ds.send(dp);
//结束
if (msg.equals("exit")){
break;
}
//接收
byte[] bt1 = new byte[1024];
//空的数据报包进行接收
DatagramPacket dp1 = new DatagramPacket(bt1, bt1.length);
//接收
ds.receive(dp1);
System.out.println("从接收端接收的信息为:"+new String(bt1,0,dp1.getLength()));
}
//关闭资源
ds.close();
}
}
接收端代码
package com.demo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Scanner;
public class 接收端 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(9000);
Scanner sc = new Scanner(System.in);
while (true) {
//接收
byte[] bt = new byte[1024];
DatagramPacket dp = new DatagramPacket(bt,bt.length);
ds.receive(dp);
String rec = new String(bt, 0, dp.getLength());
System.out.println("从发送端来的数据为:"+rec);
//结束
if (rec.equals("exit")){
break;
}
//发送
System.out.println("请输入向发送端发送的数据:");
String msg = sc.nextLine();
byte[] bt1 = msg.getBytes();
DatagramPacket dp1 = new DatagramPacket(bt1,bt1.length,dp.getAddress(),dp.getPort());
ds.send(dp1);
}
//关闭资源
ds.close();
}
}
广播地址
概述
广播地址: 255.255.255.255 所有
代码
package com.demo1;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
1.广播地址: 255.255.255.255 所有。
*/
public class 广播地址 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
byte[] bt = "大家注意听课了。。。。".getBytes();
DatagramPacket dp = new DatagramPacket(bt, bt.length, InetAddress.getByName("255.255.255.255"),9005 );
ds.send(dp);
ds.close();
}
}
组播地址
概述
1.组播地址 D类IP地址在历史上被叫做多播地址(multicast address),即组播地址
224.0.0.0到239.255.255.255
2.组播 java提供的类: MulticastSocket
3.注意:
组播必须加入组播组 ,才能接受组播信息。
joinGroup(InetAddress mcastaddr)
发送端代码
package com.demo1;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
/**
1.组播地址 D类IP地址在历史上被叫做多播地址(multicast address),即组播地址
224.0.0.0到239.255.255.255
2.组播 java提供的类: MulticastSocket
3.注意:
组播必须加入组播组 ,才能接受组播信息。
joinGroup(InetAddress mcastaddr)
*/
public class 组播地址发送端 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket();
byte[] bt = "大家注意听课了。。。".getBytes();
DatagramPacket dp = new DatagramPacket(bt, bt.length,
InetAddress.getByName("224.0.0.6"),9000);
ms.send(dp);
ms.close();
}
}
接收端代码
package com.demo1;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class 组播地址接收端 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(9000);
byte[] bt = new byte[1024];
DatagramPacket dp = new DatagramPacket(bt, bt.length);
//加入组播
ms.joinGroup(InetAddress.getByName("224.0.0.6"));
ms.receive(dp);
System.out.println("从组播地址接收到的数据为:"+new String(bt,0,dp.getLength()));
ms.close();
}
}
TCP协议
概述
TCP:传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于
字节流的传输层通信协议
使用场景:
文件传输 需要保证数据完整性
TCP协议客户端
1.步骤:
① 创建客户端对象:
Socket(InetAddress address, int port)
② 发送/接收数据
getInputStream() 读取
getOutputStream()写入
代码
package com.tcpdemo;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
1.步骤:
① 创建客户端对象:
Socket(InetAddress address, int port)
② 发送/接收数据
getInputStream() 读取
getOutputStream()写入
*/
public class 客户端 {
public static void main(String[] args) throws IOException {
Socket sc = new Socket(InetAddress.getByName("localhost"),9000);
//发送数据
OutputStream os = sc.getOutputStream();
//写出
os.write("服务器您好".getBytes());
//关闭
os.close();
sc.close();
}
}
TCP协议服务器端
1.步骤:
① 创建服务器端对象:
ServerSocket(int port)
② 等待连接:
accept() 侦听并接受到此套接字的连接。返回值就是连接到该服务器的客户端对象。
③ 读取客户端发送的信息
通过accept方法返回的Socket获取输入流。
代码
package com.tcpdemo;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
1.步骤:
① 创建服务器端对象:
ServerSocket(int port)
② 等待连接:
accept() 侦听并接受到此套接字的连接。返回值就是连接到该服务器的客户端对象。
③ 读取客户端发送的信息
通过accept方法返回的Socket获取输入流。
*/
public class 服务器端 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9000);
//等待并监听 该方法一旦执行成功,意味着三次握手已经结束。
Socket sc = ss.accept();
//读取
InputStream in = sc.getInputStream();
int value = 0;
byte[] bt = new byte[1024];
while ((value=in.read(bt))!=-1){
System.out.println(new String(bt,0,value));
}
//关闭
in.close();
ss.close();
}
}
TCP协议细节问题
概述
如果使用的是循环读取,由于写入必须到达流的末尾或文件的末尾才能取到-1,
导致循环一直无法停止跳出,代码就没办法继续执行了。需要通过以下方法进行置为流的末尾。
① shutdownInput()
② shutdownOutput()
客户端代码
package com.tcpdemo1;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
1.步骤:
① 创建客户端对象:
Socket(InetAddress address, int port)
② 发送/接收数据
getInputStream() 读取
getOutputStream()写入
2.细节问题:
如果使用的是循环读取,由于写入必须到达流的末尾或文件的末尾才能取到-1,
导致循环一直无法停止跳出,代码就没办法继续执行了。需要通过以下方法进行置为流的末尾。
① shutdownInput()
② shutdownOutput()
*/
public class 客户端 {
public static void main(String[] args) throws IOException {
Socket sc = new Socket(InetAddress.getByName("localhost"),9000);
//发送数据
OutputStream os = sc.getOutputStream();
//写出
os.write("服务器您好".getBytes());
//置于流的末尾
sc.shutdownOutput();
//接收从服务器端发来的数据
InputStream in = sc.getInputStream();
int value = 0;
byte[] bt = new byte[1024];
while ((value = in.read(bt))!=-1){
System.out.println(new String(bt,0,value));
}
//关闭
os.close();
in.close();
sc.close();
}
}
服务器端代码
package com.tcpdemo1;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
1.步骤:
① 创建服务器端对象:
ServerSocket(int port)
② 等待连接:
accept() 侦听并接受到此套接字的连接。返回值就是连接到该服务器的客户端对象。
③ 读取客户端发送的信息
通过accept方法返回的Socket获取输入流。
*/
public class 服务器端 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9000);
//等待并监听 该方法一旦执行成功,意味着三次握手已经结束。
Socket sc = ss.accept();
//读取
InputStream in = sc.getInputStream();
int value = 0;
byte[] bt = new byte[1024];
while ((value=in.read(bt))!=-1){
System.out.println(new String(bt,0,value));
}
System.out.println("=================");
//服务器端向客户端发送数据
OutputStream out = sc.getOutputStream();
out.write("客户端您好".getBytes());
//关闭
in.close();
out.close();
ss.close();
}
}
文件上传
原理
从客户端的硬盘上读取文件到客户端的java程序,然后通过java程序写入到服务器端的java程序,通过服务器端的java程序,写入到服务器的硬盘上。
客户端代码
package com.uploaddemo;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
1.创建客户端对象
2. 读取硬盘上的文件,向服务器端写入
3.关闭资源
*/
public class 客户端 {
public static void main(String[] args)throws IOException {
Socket s = new Socket(InetAddress.getByName("localhost"),9000);
//文件输入流
FileInputStream fis = new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\成功的阶梯.jpg"));
//向服务器写入
OutputStream os = s.getOutputStream();
//读取硬盘上的文件,向服务器端写入
int value =0;
byte[] bt = new byte[1024];
while ((value = fis.read(bt))!=-1){
os.write(bt,0,value);
}
//关闭资源
os.close();
fis.close();
s.close();
}
}
服务器端代码
package com.uploaddemo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
1.创建服务器端的对象
2.等待客户端的连接
3.接收从客户端来的文件,并且写入到服务器端的硬盘。
4.关闭资源
*/
public class 服务器端 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9000);
Socket s = ss.accept();
// Socket的输入流
InputStream in = s.getInputStream();
//文件输出流
FileOutputStream fos = new FileOutputStream(new File("day26b\\upload\\1.jpg"));
// 3.接收从客户端来的文件,并且写入到服务器端的硬盘。
int value = 0;
byte[] bt = new byte[1024];
while ((value = in.read(bt))!=-1){
fos.write(bt,0, value);
}
// 关闭资源
fos.close();
in.close();
ss.close();
}
}
文件上传的重名问题
概述
文件上传时,由于文件名称是相同的,新的上传的文件会覆盖原有的。解决的办法:
① window系统重命名的方式
② UUID
全球唯一标识。
randomUUID() 获取UUID
多线程下的文件上传
客户端代码
package uploaddemo1;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
1.创建客户端对象
2. 读取硬盘上的文件,向服务器端写入
3.关闭资源
*/
public class 客户端 {
public static void main(String[] args)throws IOException {
Socket s = new Socket(InetAddress.getByName("localhost"),9000);
//文件输入流
FileInputStream fis = new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\成功的阶梯.jpg"));
//向服务器写入
OutputStream os = s.getOutputStream();
//读取硬盘上的文件,向服务器端写入
int value =0;
byte[] bt = new byte[1024];
while ((value = fis.read(bt))!=-1){
os.write(bt,0,value);
}
//关闭资源
os.close();
fis.close();
s.close();
}
}
服务器端代码
package uploaddemo1;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
/**
1.创建服务器端的对象
2.等待客户端的连接
3.接收从客户端来的文件,并且写入到服务器端的硬盘。
4.关闭资源
*/
public class 服务器端 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9000);
boolean flag = true;
while (flag) {
Socket s = ss.accept();
new Thread(new Runnable() {
@Override
public void run() {
try(InputStream in = s.getInputStream();
FileOutputStream fos = new FileOutputStream(new File("day27a\\upload\\"+ UUID.randomUUID()+".jpg"));
){
// 3.接收从客户端来的文件,并且写入到服务器端的硬盘。
int value = 0;
byte[] bt = new byte[1024];
while ((value = in.read(bt))!=-1){
fos.write(bt,0, value);
Thread.sleep(2000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
ss.close();
}
}