DAY23-网络编程

网络通信的三要素:IP地址,端口号,协议

IP地址:

IPV4:4个0-255的数组来表示,每个数字占一个byte,一个IP地址占32位内存,约有43亿个IP地址。前2个或3个表示子网号

比如,当前计算机地址为10.10.22.90,子网号为10.10.22,90表示当前计算机的标识,最后一位理论上能产生256个数字,但是其中0和255有特殊含义,0表示子网号255表示广播地址,所以有效标识符有254个。

IPV6:128位,十六进制数据。

特殊IP地址:127.0.0.1,本地回环地址,表示的是当前这个计算机自己,和 " localhost " 等价。

DNS:域名解析器。

InetAddress类是用来表示IP地址对象的,该类不能直接创建对象。类中有静态方法。

static InetAddress getByName(String host) 
          在给定主机名的情况下确定主机的 IP 地址。
static InetAddress[] getAllByName(String host) 
          在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
static InetAddress getLocalHost() 
          返回本地主机
String getHostName() 
          获取此 IP 地址的主机名。
 String getHostAddress() 
          返回 IP 地址字符串(以文本表现形式)。
import java.net.InetAddress;

public class Demo3 {
	public static void main(String[] args)throws Exception {
		InetAddress add1=InetAddress.getByName("www.baidu.com");//获取指定主机的InetAddress对象
		InetAddress add2=InetAddress.getLocalHost();//获取本机的InetAddress对象
		InetAddress[] add3=InetAddress.getAllByName("www.youtube.com");//获取指定主机的所有InetAddress对象
		String s1=add1.getHostName();//获取InetAddress对象的主机名
		String s2=add1.getHostAddress();//获取InetAddress对象的地址
		
		System.out.println("add1---"+add1);
		System.out.println("add2----"+add2);
		for(InetAddress in:add3)
			System.out.println("add3---ip地址"+in.getHostAddress()+"主机名"+in.getHostName());
		System.out.println("s1---"+s1);
		System.out.println("s2---"+s2);
	}
}

端口号:用2个byte表示的一个数字,这个数字用来表示系统中每一个进程的表示。范围是0-65535(2^16),也就是说最多可以有65536个程序同时运行。程序启动时,系统会默认随机分配一个端口号,当程序运行结束后会释放这个端口号,可以自己指定端口号。

0-1024间的端口号被系统占用,不可用。

常用端口号:MySQL-3306,TomCat-8080,Oracle-1521

协议

设备间通信时,对数据封装和解析的规则。

分层处理:

应用层:HTTP,HTTPS

传输层:UDP,TCP

网络层:IP协议

物理层:硬件

UDP:面向无连接,不可靠协议,速度快,数据不能超过64K

TCP:面向有链接,可靠协议,速度慢,可以传输大文件,采用三次握手确认连接。

UDP协议:

DatagramSocket:用来表示发送和接收数据包的套接字。

构造方法摘要
  DatagramSocket() //计算机随机指定端口
          构造数据报套接字并将其绑定到本地主机上任何可用的端口。
protected DatagramSocket(DatagramSocketImpl impl) 
          创建带有指定 DatagramSocketImpl 的未绑定数据报套接字。
  DatagramSocket(int port) //自己指定端口
          创建数据报套接字并将其绑定到本地主机上的指定端口。
  DatagramSocket(int port, InetAddress laddr) 
          创建数据报套接字,将其绑定到指定的本地地址。
  DatagramSocket(SocketAddress bindaddr) 
          创建数据报套接字,将其绑定到指定的本地套接字地址。

DatagramPacket打包和拆包对象打包的参数都有4个(byte数组,数组长度,IP地址,端口号),拆包的参数只有2个(byte数组,数组长度)顶多再加上一个数组的offset

构造方法摘要
DatagramPacket(byte[] buf, int length) 
          构造 DatagramPacket,用来  接收  长度为 length 的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
          构造数据报包,用来将长度为 length 的包  发送  到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int offset, int length) 
          构造 DatagramPacket,用来  接收  长度为 length 的包,在缓冲区中指定了偏移量。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 
          构造数据报包,用来将长度为 length 偏移量为 offset 的包  发送  到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 
          构造数据报包,用来将长度为 length 偏移量为 offset 的包  发送  到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int length, SocketAddress address) 
          构造数据报包,用来将长度为 length 的包  发送  到指定主机上的指定端口号。

发送端:

  1. 创建端点对象
  2. 打包
  3. 发包
  4. 关闭端点对象
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//发送端
public class Demo4 {
	public static void main(String[] args)throws Exception {
		DatagramSocket dgs=new DatagramSocket();//1.创建端点对象,可以指定端口也可以不指定
		
		byte[] buf="这个字节数组是用来打包的".getBytes();//2.打包,用来读取数据的数组
		InetAddress in=InetAddress.getByName("localhost");//发送到哪个IP地址?
		int len=buf.length;//数组长度
		int port=8989;//通过哪个端口号发送?
		DatagramPacket dgp=new DatagramPacket(buf, len, in, port);
		
		dgs.send(dgp);//3.发包
		
		System.out.println("发送完成");
		System.out.println("-------------------------");
		//////////////////////////接收回执,转为接收端//////////////////////////////////
		byte[] by=new byte[30];
		DatagramPacket dg=new DatagramPacket(by, by.length);//接包
		dgs.receive(dg);
		
		//拆包
		String s1=new String(dg.getData());
		int length=dg.getLength();
		String add=dg.getAddress().getHostAddress();
		int port2=dg.getPort();
		System.out.println(s1);
		System.out.println(length);
		System.out.println(add);
		System.out.println(port2);
		System.out.println("----已收到回执-----");
		
		dgs.close();//4.关闭端点对象
	}
}

接收端:

  1. 创建端点对象
  2. 接包
  3. 拆包
  4. 关闭端点对象
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//接收端
public class Demo5 {
	public static void main(String[] args)throws Exception {
		DatagramSocket dgs=new DatagramSocket(8989);//1.创建端点对象,接收端必须指定端口,就是发送端打包的时候的端口
		
		//2.接包,发包接包都是DatagramPacket对象的功能,所以要先创建这个对象
		byte[] buf=new byte[30];
		int length=buf.length;
		DatagramPacket dgp=new DatagramPacket(buf, length);//接收端只需要两个参数就可以了,发送端需要四个参数
		
		dgs.receive(dgp);//开始接包!!!
		
		//3.拆包
		String data=new String(dgp.getData());//获取发送端发送的数据,由于接受的是字节数组,所以要转换成字符串
		InetAddress address=dgp.getAddress();//获取发送端的IP地址,返回的是InetAddress对象
		String add=address.getHostAddress();//获取IP地址的字符串形式
		int port=dgp.getPort();//获取发送端的端口号,如果发送端定义了值就返回他,如果没定义过就返回计算机随机分配的值
		int len=dgp.getLength();//返回将要发送或接收到的数据长度,发送端也可以调用这个方法
		
		System.out.println(data);
		System.out.println(add);
		System.out.println(port);
		System.out.println(len);
		System.out.println("---接收完成---");
		////////////////////////////发送回执,转变为发送端////////////////////////////////
		//端点对象已经创建过了,可以直接打包发包
		byte[] by="信息已收到!".getBytes();
		DatagramPacket dg=new DatagramPacket(by, by.length,address,port);//打包,打包的方法都有四个参数
		dgs.send(dg);//发包
		System.out.println("----回执已发送成功----");
		
		dgs.close();//4.关闭端点对象
	}
}

TCP

注意!!!不管是客户端还是服务端,只要是在使用循环读取另外一方发来的数据,发送方  一定要记得最后使用  s.shutdownOutput()  通知接收数据的一方,数据发送完成。否则接收数据一方的循环就无法停止。

客户端

  1. 创建Socket对象
  2. 获取输出流
  3. 向服务端写入数据
  4. 关闭Socket对象,只需要关闭Socket和自己定义的输入输出流即可,注意服务端获取到的Socket对象也需要关闭
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

//上传文件
public class Client2 {
	public static void main(String[] args) throws Exception{
		Socket so=new Socket("localhost", 8989);
		OutputStream os=so.getOutputStream();//outputStream是抽象类,但是他自己也有方法,可以直接用
		FileInputStream fis=new FileInputStream("D:\\Items.txt");
		byte[] by=new byte[1024];
		int len=0;
		while ((len=fis.read(by))!=-1) {
			os.write(by, 0, len);
		}
		System.out.println("数据写出已完毕!");
		so.shutdownOutput();
//		os.close();通道的输出流不能关闭,否则连接就断了
		fis.close();
		///////////////////////接收回执信息///////////////////////////////
		InputStream in=so.getInputStream();
		byte[] byt=new byte[20];
		in.read(byt);
		System.out.println(new String(byt));
//		in.close();通道只需要关闭socket就行,其他手动添加的输出流自行关闭
		so.close();
	}
}

服务端

  1. 创建ServerSocket对象
  2. 接收客户端请求,并与客户端建立连接
  3. 获取通道中的输入流
  4. 读取客户端发送的数据
  5. 关闭,只需要关闭和ServerSocket对象和自己定义的输入输出流即可,获取到的客户端的Socket对象也要关闭!
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

//接收上传的文件并保存在本地
public class Server2 {
	public static void main(String[] args) throws Exception{
		ServerSocket ss=new ServerSocket(8989);
		Socket so=ss.accept();//接收请求,与客户端建立连接
		InputStream is=so.getInputStream();
		FileOutputStream fos=new FileOutputStream("D:\\upload.txt");
		byte[] by=new byte[1024];
		int len=0;
		while ((len=is.read(by))!=-1) {
			fos.write(by, 0, len);
		}
//		so.shutdownInput();//结束输入流
		System.out.println("文件读取结束,已保存本地");
		////////////////////////////回执////////////////////////////
		OutputStream os=so.getOutputStream();
		os.write("文件上传成功!".getBytes());
		System.out.println("回执已发送");
//		is.close();不需要关闭
//		os.close();不需要关闭
		so.close();
		fos.close();
		ss.close();
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42837554/article/details/88697457
今日推荐