1、网络协议的概述编程
多台计算机的链接和“交流”离不开网络的支持,而就像道路同样,为了保证传输的效率和安全,网络的传输也需
要必定得规则。只有双方都知足这个规则才能创建联系。如今应用最普遍的就是目前应用最普遍的是TCP/IP协议
(Transmission Control Protocal/Internet Protoal),中文全名为:传输控制协议/英特网互联协议。它包含了
TCP协议和IP协议,UDP协议等。而为了保证传输先后数据的一致性,在传输的过程当中须要在原数据的头尾部添加一
些数据。TCP/IP协议一共分为4层:数组
链路层:链路层主要规定了物理传输通道的规则、一般是某些网络连接设备的驱动协议,如:光纤、网线。
网络层:网络层是TCP/IP协议的核心,它主要用于将传输的数据进行分组并将分组数据发送到目标计算机或者网络
(进行数据的分包)。
传输层:主要用于程序之间得的网络通信,能够采用TCP协议或者是UDP协议(创建连接)。
应用层:主要用于应用程序的协议,如http协议。安全
2、IP地址和端口号 服务器
想要进行应用程序之间通讯,和咱们平时串门的思想是同样的,你首先要知道你的朋友住在哪一个小区(IP地址)
,知道了他家的小区地址以后你还须要知道你朋友家的具体门牌号(端口号)才能进入家门进行深刻的交流。目前当
前IP地址普遍使用的版本是IPv4,它是由4个字节大小的二进制数来表示。可是随着互联网普及的愈来愈广IPv4的方式
已经不能知足咱们的需求了,所以IPv6就应运而生了,IPv6使用16个字节表示IP地址,它所拥有的地址容量约是IPv4
的8×1028倍,这样解决了IP地址不够用的问题。经过IP地址能够链接到指定计算机,若是想访问目标计算机中的某个应
用程序,则须要指定对应端口号。在计算机中,不一样的应用程序是经过端口号区分的。端口号是用两个字节(16位的二
进制数)表示的,它的取值范围是0~65535,其中,0~1023之间的端口号用于一些知名的网络服务和应用,用户的普通
应用程序须要使用1024以上的端口号,从而避免端口号被另一个应用或服务所占用。网络
3、InetAddress类 socket
Java为了咱们编程更加的方便,为咱们的网络编程提供了一些技术支持。InetAddress类用于封装一个IP地址并提供了
一些关于IP地址经常使用的方法:
一、getByName:在给定主机名的状况下肯定主机的 IP 地址 - 返回值为InetAddress对象。
二、getHostName():获取此 IP 地址的主机名 - 返回值为字符串。
三、getHostAddress():返回 IP 地址字符串。
四、getLocalHost(): 返回本地主机 - 返回值为InetAddress对象。
举例:ide
1 //给定主机名返回主机IP 2 InetAddress i=InetAddress.getByName("DESKTOP-4DDBUKG"); 3 System.out.println(i); 4 //获取此IP地址的主机名 5 String hostName = i.getHostName(); 6 System.out.println(hostName); 7 //返回IP地址的字符串 8 String address = i.getHostAddress(); 9 System.out.println(address); 10 //返回本地主机 11 InetAddress localHost = InetAddress.getLocalHost(); 12 System.out.println(localHost);
4、UDP协议post
UDP是无链接通讯协议,即在发送数据时无论接收端接不接收他都发送数据,而接收端在接收数据时也不会给发送端一
个反馈。由于UDP协议消耗资源小,通讯效率高,因此一般都会用于音频、视频和普通数据的传输例如视频会议都使用
UDP协议,由于这种状况即便偶尔丢失一两个数据包,也不会对接收结果产生太大影响。可是在传输重要数据时不建议使用
UDP协议,由于UDP是无链接通讯协议不能保证数据的完整性。网站
(一)、DatagramSocket类this
DatagramSocket类表示用来发送和接收数据报包的套接字。数据报套接字是包投递服务的发送或接收点。因此
DatagramSocket类能够理解为发送快递的收件人和寄件人,在建立发送端和接收端的DatagramSocket对象时使用的
是不一样的构造方法:
一、DatagramSocket():该构造方法用于建立发送端的DatagramSocket对象,系统会给他分配一个没有被其它网络程
序所使用的端口号。
二、DatagramSocket(int port) :该构造方法既可用于建立接收端的DatagramSocket对象,又能够建立发送端的
DatagramSocket对象,在建立接收端的DatagramSocket对象时,必需要指定一个端口号,这样就能够监听指定的端口。
DatagramSocket类的经常使用方法:
一、今后套接字接收数据报包:receive(DatagramPacket p)。
二、今后套接字发送数据报包:send(DatagramPacket p) 。
(二)DatagramPacket类
UDP通讯的过程其实和发快递很像,知道了收件人和寄件人后还须要对“货物”进行打包,而DatagramPacket类就是
至关于“快递员”,用于封装UDP通讯中发送或者接收的数据。DatagramPacket类的构造方法与DatagramSocket类的相似
接收端的构造方法只须要接收收到的数据,而发送端的构造方法不只要存放要发送的数据,还要指定接收端的IP和端口
号。
一、接收端 - 构造 DatagramPacket,用来接收长度为 length 的数据包:DatagramPacket(byte[] buf, int length)
二、发送端 - 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号:
DatagramPacket(byte[] buf, int length, SocketAddress address)
其经常使用的方法:
一、返回某台机器的 IP 地址,此IP将要发往该机器或者是从该机器接收到的:getAddress()
二、返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的:getPort()
三、返回数据缓冲区:getData()
四、返回将要发送或接收到的数据的长度:getLength()
举例:
*发送端
1 public static void main(String[] args) throws IOException { 2 // 获取DatagramSocket类的对象ds 3 DatagramSocket ds = new DatagramSocket(); 4 // 死循环发送信息 5 while (true) { 6 // 准备要发送的数据 7 String s = "萨拉黑有"; 8 // 将其转换成byte数组 9 byte[] bs = s.getBytes(); 10 // 获取数组的长度 11 int length = bs.length; 12 // 根据IP地址获取InetAddress对象it 13 InetAddress it = InetAddress.getByName("192.168.1.146"); 14 // 准备端口号 15 int post = 8888; 16 // 建立DatagramPacket对象,传入准备好的数据、数据长度、IP地址、端口号进行打包 17 DatagramPacket datagramPacket = new DatagramPacket(bs, length, it, post); 18 // 调用send方法将准备好的数据数据发送出去,由于在一直发送数据因此没有关闭资源 19 ds.send(datagramPacket); 20 } 21 }
*接收端
1 public static void main(String[] args) throws IOException { 2 // 建立DatagramSocket对象,设置端口号进行监听 3 DatagramSocket ds = new DatagramSocket(8888); 4 // 循环接收数据 5 while (true) { 6 // 准备接受数据的容器 7 byte[] buf = new byte[1024]; 8 // 建立DatagramPacket对象用来接收数据、传入容器和容器的长度 9 DatagramPacket packet = new DatagramPacket(buf, buf.length); 10 // 调用receive方法接收数据 11 ds.receive(packet); 12 // 获取发送端的InetAddress对象 13 InetAddress address = packet.getAddress(); 14 // 获取传入数据的长度 15 int length = packet.getLength(); 16 // 输出发送端IP地址和发送的内容 17 System.out.println("---->" + address.getHostAddress() + " 内容:" + new String(buf, 0, length)); 18 } 19 }
5、TCP协议
TCP做为另外一种经常使用的通讯协议,与UDP协议的相同点是都能实现两台计算机之间的通讯,通讯的两端都须要建立socket对象。
而二者不一样的是UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间能够任意地发送数据。而TCP通讯是严格区分
客户端与服务器端的,在通讯时,必须先由客户端去链接服务器端才能实现通讯,服务器端不能够主动链接客户端,而且服务器
端程序须要事先启动,等待客户端的链接。而JAVA为了方便咱们的开发提供给咱们2个用于实现TCP程序的类,一个是ServerSocket类
,用于表示服务器端,一个是Socket类,用于表示客户端。
(一)、ServerSocket类
TCP协议进行通信时首先要建立表明服务器端的ServerSocket对象,等待客户端的链接。而后建立表明客户端的Socket对象向服务
器端发出链接请求,服务器端响应请求,二者创建链接开始通讯。
ServerSocket类的经常使用构造方有 - 建立绑定到特定端口的服务器套接字:ServerSocket(int port)
其经常使用方法:
一、返回值为Socket对象,侦听并接受到此套接字的链接:accept()
二、关闭此套接字:close()
三、返回此服务器套接字的本地地址:getInetAddress()
ServerSocket对象负责监听某台计算机的某个端口号,在建立ServerSocket对象后,须要继续调用该对象的accept()方法,接收
来自客户端的请求。当执行了accept()方法以后,服务器端程序会发生阻塞,直到客户端发出链接请求,accept()方法才会返回一个
Scoket对象用于和客户端实现通讯,程序才能继续向下执行。
(二)、Socket类
Socket类实现客户端套接字(TCP客户端程序),其经常使用的构造方法有:
一、建立一个流套接字并将其链接到指定 IP 地址的指定端口号 - 根据InetAddress对象和端口号port建立:
Socket(InetAddress address, int port)
二、建立一个流套接字并将其链接到指定主机上的指定端口号 - 根据IP的字符串和端口号port建立:
Socket(String host, int port)
Socket类的经常使用方法有:
一、返回值为int,返回的是Socket对象与服务器端链接的端口号:getPort()
二、返回值为InetAddress类型的对象,获取Socket对象绑定的本地IP地址:getLocalAddress()
五、关闭此套接字:close()
六、返回值为InputStream类型的输入流对象,返回值为此套接字的输入流,用于读取数据:getInputStream()
七、返回值为OutputStream类型的输出流对象,返回值为此套接字的输出流,用于数据的写入:getInputStream()
当客户端和服务端创建链接后,数据是以IO流的形式进行交互的,从而实现通讯。
举例:
*客户端
1 public static void main(String[] args) throws IOException, Exception { 2 // 建立Socket客户端对象 3 Socket socket = new Socket("192.168.14.81", 9999); 4 // 获取OutputStream对象,准备发送数据 5 OutputStream stream = socket.getOutputStream(); 6 // 准备发送的数据 7 String s = "我啦啦啦啦啦"; 8 // 将字符转换成byte发送 9 stream.write(s.getBytes()); 10 // 关闭资源 11 socket.close(); 12 stream.close(); 13 }
*服务器端
1 public static void main(String[] args) throws IOException { 2 // 建立ServerSocket服务器端对象,设置端口号进行监听 3 ServerSocket ss = new ServerSocket(9999); 4 // 调用accept方法进行监听,这里之后的代码先不会执行,和客户端创建链接以后在继续执行 5 Socket accept = ss.accept(); 6 // 根据accept对象建立InputStream对象用来接收数据 7 InputStream stream = accept.getInputStream(); 8 // 准备接收数据的容器 9 byte[] b = new byte[1024]; 10 // 接收数据据的长度 11 int len; 12 // 往b里读取数据 13 len = stream.read(b); 14 // 获取客户端的InetAddress对象 15 InetAddress inetAddress = accept.getInetAddress(); 16 // 输出客户端的IP 17 System.out.println("-------->" + inetAddress.getHostAddress()); 18 // 输出接收的数据从0到len 19 System.out.println(new String(b, 0, len)); 20 // 关闭资源,由于服务器在正常状况下不会关闭,因此这里指关闭流资源 21 stream.close(); 22 }
模拟网站登陆举例:
*用户类
1 public class User { 2 private String username; 3 private String pwd; 4 5 public User() { 6 super(); 7 // TODO Auto-generated constructor stub 8 } 9 10 public User(String username, String pwd) { 11 super(); 12 this.username = username; 13 this.pwd = pwd; 14 } 15 16 public String getUsername() { 17 return username; 18 } 19 20 public void setUsername(String username) { 21 this.username = username; 22 } 23 24 public String getPwd() { 25 return pwd; 26 } 27 28 public void setPwd(String pwd) { 29 this.pwd = pwd; 30 } 31 @Override 32 public boolean equals(Object obj) { 33 if (this == obj) 34 return true; 35 if (obj == null) 36 return false; 37 if (getClass() != obj.getClass()) 38 return false; 39 User other = (User) obj; 40 if (pwd == null) { 41 if (other.pwd != null) 42 return false; 43 } else if (!pwd.equals(other.pwd)) 44 return false; 45 if (username == null) { 46 if (other.username != null) 47 return false; 48 } else if (!username.equals(other.username)) 49 return false; 50 return true; 51 } 52 }
*模拟的用户数据
1 public class Obj { 2 private static ArrayList<User> arr = new ArrayList<>(); 3 static { 4 arr.add(new User("admin", "123456")); 5 arr.add(new User("lisi", "1111")); 6 arr.add(new User("wang5", "3333")); 7 arr.add(new User("lisi", "000000")); 8 //System.out.println(arr); 9 10 } 11 public static ArrayList<User> get() { 12 return arr; 13 } 14 }
*客户端
1 public static void main(String[] args) throws IOException, IOException { 2 // 根据IP地址和端口号建立客户端对象 3 Socket socket = new Socket("192.168.14.27", 8888); 4 // 键盘录入用户名和密码 5 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 6 System.out.println("请输入用户名"); 7 String username = reader.readLine(); 8 System.out.println("请输入密码"); 9 String pwd = reader.readLine(); 10 // 根据socket对象建立字符输出流,为了方便用PrintWriter类传输数据 11 PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); 12 // 将用户名和密码写到服务器 13 writer.println(username); 14 writer.println(pwd); 15 // 根据socket建立BufferedReader用来接收返回的数据 16 BufferedReader reader2 = new BufferedReader(new InputStreamReader(socket.getInputStream())); 17 // 读取返回的数据 18 String line = reader2.readLine(); 19 // 显示登陆提示 20 System.out.println(line); 21 // 关闭资源 22 reader2.close(); 23 reader.close(); 24 writer.close(); 25 socket.close(); 26 }
*服务器
public static void main(String[] args) throws IOException { // 建立服务端ServerSocket对象,设置端口号 ServerSocket socket = new ServerSocket(8888); // 调用accept方法,返回Socket对象 Socket accept = socket.accept(); // 根据Socket对象获取InputStream对象对其转型,建立BufferedReader对象 BufferedReader reader = new BufferedReader(new InputStreamReader(accept.getInputStream())); // 读取客户端传来的用户名和密码 String username = reader.readLine(); String pwd = reader.readLine(); // 根据传过来的用户名和密码建立User对象 User user = new User(username, pwd); // 获取OutputStream()对象将其转换,准备把处理的结果返回给客户端 PrintWriter writer = new PrintWriter(accept.getOutputStream(), true); // 获取正确的用户集合 ArrayList<User> list = Obj.get(); // 判断根据传过来的用户名和密码建立User对象是否在集合里存在 if (list.contains(user)) { // 存在,返回登录成功提示 writer.println("登录成功"); } else { // 不存在,返回登陆失败提示 writer.println("登陆失败"); } // 关闭资源 writer.close(); accept.close(); }