网络编程其实就是要两台计算机之间进行数据传递。
那么两台计算机之间如何进行数据传递呢?
依赖于网络三要素
网络三要素
1.IP地址
2.端口号
3.协议
IP地址
IP地址全称互联网协议地址,是设备在网络中的唯一标识,注意域名会先经过DNS服务器解析成IP地址返回给我们的主机,然后在拿到IP地址后才能访问相应网址。
IP地址分为IPV4和IPV6
IPv4一共32位(4个字节),分为4组,采用点分十进制法表示。
由于IPV4只有32位至多能表示2^32,约等于42亿的地址,不够用了,然后推出了IPv6。
IPv4一共128位(16个字节),分为8组,采用冒分16进制法表示,会省略前导0,若是多个连续的0会用::表示。
在java中InetAddress类代表IP地址
获得实例对象的静态方法 | 通过实例对象获得IP地址的方法 | 通过实例对象获得主机名的方法 |
---|---|---|
InetAddress.getByName(主机名) | getHostAddress() | getHostName() |
端口号
端口号是应用程序在设备中的唯一标识
端口号是一个2个字节表示的整数,范围在0-65535(0-2^16-1)
其中0-1023被知名网络应用使用了,我们自己使用要使用1024及以上的端口号
协议
协议是计算机中连接和通信的规则
UDP协议
定义概述:
用户数据报协议(User Datagram Protocol)
UPD是面向无连接通信协议
特点:
速度快,一次至多传输64K,数据不安全,易丢失数据。
编程案例:
public class ClientDemo { public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); //1.找到快递公司 DatagramSocket ds = new DatagramSocket(); String s = null; while ((s = sc.nextLine()).equals("886") == false) { byte[] bytes = s.getBytes(); //2.包装物品,填写地址 DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 10000); //3.发送物品 ds.send(datagramPacket); } //4.释放资源 ds.close(); } } public class SeverDemo { public static void main(String[] args) throws IOException { //1.找到快递公司 DatagramSocket socket = new DatagramSocket(10000); while (true) { byte[] bytes = new byte[1024]; //2.准备一个箱子装东西 DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length); //3.接受快递,并装到新箱子里面去 socket.receive(datagramPacket); //4.获得物品 byte[] data = datagramPacket.getData(); int length = datagramPacket.getLength(); System.out.println(new String(data,0,length)); } //5.释放资源 } }
注意:
1.要先启动接收端,才能启动发送端发送
2.接收端启动以后会一直停在接收方法处,等待发送端发送
3.在接收数据时要调用
UDP的三种通讯方式
1.单播:电脑通过路由器发送到一台电脑,1对1
单播地址就是接收方设备的ip地址
2.组播:电脑通过路由器发送到一组电脑,1对多
组播地址:224.0.0.0 - 239.255.255.255
其中224.0.0.0-224.0.0.255为预留地址,我们要使用只能从224.0.1.0开始使用
3.广播:电脑通过路由器发送到所有电脑,1对所有
广播地址:255.255.255.255
单播代码实例
public class ClientDemo {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
//1.找到快递公司
DatagramSocket ds = new DatagramSocket();
String s = null;
while ((s = sc.nextLine()).equals("886") == false) {
byte[] bytes = s.getBytes();
//2.包装物品,填写地址
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("127.0.0.1"), 10000);
//3.发送物品
ds.send(datagramPacket);
}
//4.释放资源
ds.close();
}
}
public class SeverDemo {
public static void main(String[] args) throws IOException {
//1.找到快递公司
DatagramSocket socket = new DatagramSocket(10000);
while (true) {
byte[] bytes = new byte[1024];
//2.准备一个箱子装东西
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
//3.接受快递,并装到新箱子里面去
socket.receive(datagramPacket);
//4.获得物品
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
System.out.println(new String(data,0,length));
}
//5.释放资源
}
}
组播代码实例
public class CilentDemo01 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
String s = "组播";
byte[] bytes = s.getBytes();
InetAddress ip = InetAddress.getByName("224.0.1.0");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port);
ds.send(dp);
ds.close();
}
}
public class SeverDemo01 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(10000);
DatagramPacket datagramPacket = new DatagramPacket(new byte[1024], 1024);
//把当前计算机加入到组里面
ms.joinGroup(InetAddress.getByName("224.0.1.0"));
ms.receive(datagramPacket);
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
System.out.println(new String(data,0,length));
ms.close();
}
}
广播代码实例
public class CilentDemo02 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
String s = "广播";
byte[] bytes = s.getBytes();
InetAddress ip = InetAddress.getByName("255.255.255.255");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port);
ds.send(dp);
ds.close();
}
}
public class SeverDemo02 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10000);
DatagramPacket datagramPacket = new DatagramPacket(new byte[1024], 1024);
ds.receive(datagramPacket);
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
System.out.println(new String(data,0,length));
ds.close();
}
}
总结:
发送端代码:
单播、组播、广播的发送方都是1,代码也基本一致,只是DatagramPacket中的ip地址不同,单播传入的ip地址是接收方设备的ip地址,组播则是组播地址224.0.0.0-239.255.255.255,其中224.0.0.0-224.0.0.255为预留地址,我们程序中使用的是224.0.1.0-239.255.255.255,广播则是地址255.255.255.255
接收端代码:
单播和广播的接收端代码一致使用的是DatagramSocket,而组播使用的是MulticastSocket,因为多了一个把当前计算机加入到组中的操作,需要该类里面的joinGroup(InetAddress对象),InetAddress是那个组播地址的对象就加入到哪个组中,其他代码差不多一致,都是使用DatagramPacket来装数据。
TCP协议
定义概述
全称Transmisstion Control Protocol传输控制协议
TCP是面向连接的通信协议
特点
速度慢,没有大小限制,数据安全。
tcp编程案例
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.创建Socket对象
Socket s = new Socket("127.0.0.1",10010);
//2.获取输出流写出数据
OutputStream os = s.getOutputStream();
os.write("我是你爸爸".getBytes());
//3.关闭资源,输出流关闭时会往接收端写一个结束标记
os.close();
s.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建Socket对象
ServerSocket ss = new ServerSocket(10010);
//2.等待客户端连接
Socket accept = ss.accept();
//3.获取输入流对象,读取数据
InputStream is = accept.getInputStream();
byte[] bytes = new byte[1024];
int len = 0;
while((len = is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
System.out.println("啊啊啊啊啊");
//4.关闭流
is.close();
ss.close();
}
}
注意:
1.accept()方法是阻塞的,会等待客户端的连接
2.tcp协议的客户端和服务端是通过三次握手来确保连接建立的
3.read()方法也是阻塞的,当客户端输出流关闭之前,没有获得结束标记,该方法会陷入阻塞,当输出流关闭之后客户端会给服务端写一个结束标记,此时read方法读取到结束标记-1才会结束循环
4.断开连接时通过四次挥手来确定连接终止
三次握手
四次挥手
挥手为什么比握手多一次?
当前客户端发送断开连接请求之后,服务器接受并响应收到消息,然后先处理数据,再确认断开,多了一个处理数据的过程。
客户端服务器数据响应案例
客户端上传文件到服务器,服务器响应一个数据
public class ClientDemo2 {
public static void main(String[] args) throws IOException {
//1.创建Socket
Socket s = new Socket("127.0.0.1",10020);
//2.从本地读取数据文件边读边写
BufferedInputStream bi = new BufferedInputStream(new FileInputStream("D:\\project\\java\\demo1\\A\\1.txt"));
OutputStream os = s.getOutputStream();
int b ;
while((b = bi.read())!=-1){
os.write(b);
}
s.shutdownOutput();
//3.等待服务器响应的数据,用输入流读取
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = br.readLine())!=null){
System.out.println(line);
}
//4.关闭流
//本地流要手动关闭
bi.close();
//网络流只需要关闭socket
s.close();
}
}
public class ServerDemo2 {
public static void main(String[] args) throws IOException {
//1.创建Socket对象
ServerSocket ss = new ServerSocket(10020);
//2.等待客户端连接
Socket accept = ss.accept();
//3.获取输入流对象,读取数据,并写入到本地
InputStream is = accept.getInputStream();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\project\\java\\demo1\\B\\2.txt"));
int c;
while((c = is.read())!=-1){
bos.write(c);
}
//4.获取输出流对象,写数据给客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("上传成功");
bw.newLine();
bw.flush();
//5.关闭流
bos.close();
accept.close();
ss.close();
}
}
注意:
1.网络流是指与socket有关在网络中输入输入的流,本地流是将程序与本地进行输入输出的流
2.网络流的关闭只需要关闭socket对象即可,本地流需要手动关闭
3.网络流写数据时记得shutdownOutput关闭流并写结束标记