什么是网络协议分层思想?系统概念性就不说了,打个比方说将军想向士兵传达命令,将军需要先从校军官衔传达命令,再由校军官衔传达给尉军官衔以此类推,最后传达给士兵。这就是分层思想!
1、各层次之间相互独立,每层之间都有相应的接口,链接上下层
2、若任意一层发生变化只要层间接口关系保持不变,则该层的上下层均不受影响
3、若整个的系统被分解为若干个相对独立的子系统即分层思想,在进行调试和维护时,可以对每一层进行单独的调试,并不因为某一层的缘故从而导致整个系统瘫痪
TCP/IP协议里最重要的一点就是分层。TCP/IP协议族按层次分别为 应用层,传输层,网络层,数据链路层,物理层。当然也有按不同的模型分为4层或者7层的。
物理层
该层负责 比特流在节点之间的传输,即负责物理传输,这一层的协议既与链路有关,也与传输的介质有关。通俗来说就是把计算机连接起来的物理手段。
数据链路层
控制网络层与物理层之间的通信,主要功能是保证物理线路上进行可靠的数据传递。为了保证传输,从网络层接收到的数据被分割成特定的可被物理层传输的帧。帧是用来移动数据结构的结构包,他不仅包含原始数据,还包含发送方和接收方的物理地址以及纠错和控制信息。其中的地址确定了帧将发送到何处,而纠错和控制信息则确保帧无差错到达。如果在传达数据时,接收点检测到所传数据中有差错,就要通知发送方重发这一帧。
网络层
决定如何将数据从发送方路由到接收方。网络层通过综合考虑发送优先权,网络拥塞程度,服务质量以及可选路由的花费等来决定从网络中的A节点到B节点的最佳途径。即建立主机到主机的通信。
传输层
该层为两台主机上的应用程序提供端到端的通信。传输层有两个传输协议:TCP(传输控制协议)和 UDP(用户数据报协议)。其中,TCP是一个可靠的面向连接的协议,udp是不可靠的或者说无连接的协议
应用层
应用程序收到传输层的数据后,接下来就要进行解读。解读必须事先规定好格式,而应用层就是规定应用程序的数据格式。主要的协议有:HTTP.FTP,Telent等
IP地址用于在TCP/IP通信协议中标记每台计算机的地址,通常用于十进制来表示,如192.168.1.100。但是在计算机内部,IP地址是一个32位的二进制数值,如11000000 10101000 00000001 00000110(192.168.1.6)。
每台电脑上的IP地址都是独一无二的,每台电脑上不同的应用程序可以分成不同的端口,端口又可以分TCP、UDP,每一个各有65536(即:2^16)个
在三次握手之后,A和B都能确定这么一件事: 我说的话,你能听到; 你说的话,我也能听到。 这样,就可以开始正常通信了,如果是两次,那将无法确定。
(1)TCP:
ServerSocket端
1、建立ServerSocket服务器端口
2、调用ServerSocket类中的accept()方法,等待接收
3、建立InputStream输入、OutputStream输出通道
4、把字节数据封装到DataInputStream、DataOutputStream中
5、再调用DataInputStream类中readUTF()方法读取数据,DataOutputStream类中writeUTF()写入数据
6、关闭流通道
代码如下:
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class TestSockServer { public static void main(String[] args) { InputStream in=null; OutputStream out=null; try { //1、建立ServerSocket服务器端口 ServerSocket ss=new ServerSocket(7777); //2、调用ServerSocket类中的accept()方法,等待接收 Socket socket=ss.accept(); // 3、建立InputStream输入、OutputStream输出通道 in=socket.getInputStream(); out=socket.getOutputStream(); //4、把字节数据封装到DataInputStream、DataOutputStream中 DataInputStream dis=new DataInputStream(in); DataOutputStream dos=new DataOutputStream(out); //5、再调用DataInputStream类中readUTF()方法读取数据,DataOutputStream类中writeUTF()写入数据 String s=null; if((s=dis.readUTF())!=null){ System.out.println(s); System.out.println("from:"+socket.getInetAddress()); System.out.println("Port:"+socket.getPort()); } dos.writeUTF("hi,hello"); //6、关闭流通道 dos.close(); dis.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }Clinet端
1、建立socket端口与IP地址,注意Clint端比Server多个IP地址
2、建立输入、输出流通道
3、把字节数据封装到DataInputStream、DataOutputStream中
4、调用DataInputStream类中readUTF()方法读取数据,DataOutputStream类中writeUTF()写入数据
5、关闭流通道
代码如下:
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class TestSockClinet { public static void main(String[] args) throws IOException { InputStream is=null; OutputStream os=null; try { //1、建立socket端口与IP地址,注意Clint端比Server多个IP地址 Socket socket=new Socket("localhost",7777); //2、建立输入、输出流通道 is=socket.getInputStream(); os=socket.getOutputStream(); //3、把字节数据封装到DataInputStream、DataOutputStream中 DataInputStream dis=new DataInputStream(is); DataOutputStream dos=new DataOutputStream(os); //4、调用DataInputStream类中readUTF()方法读取数据,DataOutputStream类中writeUTF()写入数据 dos.writeUTF("hei"); String s=null; if((s=dis.readUTF())!=null); System.out.println(s); //5、关闭流通道 dis.close(); dos.close(); socket.close(); } catch (UnknownHostException e) { e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); } } }TCP中Server端与Client端写法基本上大同小异,唯一的区别就在于Server端多个accept()方法、Client端多个IP地址,启动程序之前须先启动Server端再启动Celient
Server端
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class TalkServer { public static void main(String[] args) throws IOException { Socket socket=null; ServerSocket ss=null; try { ss=new ServerSocket(4700);//建立服务器 socket=ss.accept();//建立服务器端口连接 } catch (Exception e) { System.out.println("can not listen to:"); System.out.println("Error"+e);//错误异常 System.exit(0);//退出 } //1)建立socket输入通道,将对话输入进来 BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream())); //2)显示Cline端 System.out.println("Cline:"+is.readLine()); //3)建立socket输出通道,将对话传送出去 PrintWriter pw=new PrintWriter(socket.getOutputStream()); //BufferedWriter bw=new BufferedWriter(new OutStreamReader(socket.getOutStream())); //4)键盘输入转化成字符输入流 BufferedReader sin=new BufferedReader(new InputStreamReader(System.in)); String s;//null s=sin.readLine();//读取一行 //5)显示对话框 while(!s.equals("bye")){ //如果键盘不等于bye为true即键盘输入bye结束 pw.println(s); //将在键盘输入的字符串传送到socket端口 pw.flush(); //缓冲 System.out.println("Server:"+s); System.out.println("Clinet:"+is.readLine()); s=sin.readLine(); } is.close(); socket.close(); ss.close(); } }Client端
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class TalkClient { public static void main(String[] args) { try { //1)建立socket端口 Socket socket=new Socket("127.0.0.1",4700); //2)建立socket输出通道,将对话传送出去 PrintWriter pw=new PrintWriter(socket.getOutputStream()); //3)建立socket输入通道,将对话输入进来 BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream())); //4)键盘输入转化成字符输入流 BufferedReader sin=new BufferedReader(new InputStreamReader(System.in)); String s; s=sin.readLine(); //5) while(!s.equals("bye")){ pw.println(s); pw.flush(); System.out.println("Clinet:"+s); System.out.println("Server:"+is.readLine()); s=sin.readLine(); } pw.close(); is.close(); socket.close(); } catch (Exception e) { System.out.println("Error"+e); } } }
(2)UDP
1、UDP和TCP不同,UDP中的Server端和Client端都有着各自的端口,Client端在发包时须于Server端接口一致
2、UDP通过DatagramPacket类调用receive()方法接收数据,DatagramSocket调用send()方法发送数据。与TCP建立流通道不同
3、TCP是通过流来进行传送输入数据,UDP是通过基本数据类型包装成数组进行传送输入
UDPServer端
1、新建数组
2、新建DatagramPacket类将数组存储
3、创建UDP端口5678
4、调用DatagramSocket类中的方法receive()接收数据包
5、将接收到的数据包转化成数组
6、DataInputStream调用readLong()方法读取数据
代码如下
import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class TestUDPServer2 { public static void main(String[] args) throws Exception { //1、新建数组 byte b[]=new byte[1024]; //2、新建DatagramPacket类将数组存储 DatagramPacket dp=new DatagramPacket(b,b.length); //3、创建UDP端口5678 DatagramSocket ds=new DatagramSocket(5678); //4、调用DatagramSocket类中的方法receive()接收数据包 while(true){ ds.receive(dp);//从此套接字接收数据包 //5、将接收到的数据包转化成数组 ByteArrayInputStream bais=new ByteArrayInputStream(b); //6、DataInputStream调用readLong()方法读取数据 DataInputStream dis=new DataInputStream(bais); System.out.println(dis.readLong()); } } }UDPClient端
1、新建long类型属性
2、将发送的数据包转化成数组
3、将数组发送包存储在DataOutputStream数据中,并写入
4、调用ByteArrayOutputStream.toByteArray()方法存储在数组当中
5、调用DatagramPacket.send()方法发送数据包
代码如下:
import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; public class TestUDPClinet2 { public static void main(String[] args)throws Exception{ //1、新建long类型属性 long n=10000L; //2、将发送的数据包转化成数组 ByteArrayOutputStream baos=new ByteArrayOutputStream(); //3、将数组发送包存储在DataOutputStream数据中,并写入 DataOutputStream dos=new DataOutputStream(baos); dos.writeLong(n); //4、调用ByteArrayOutputStream.toByteArray()方法存储在数组当中 byte [] buf=baos.toByteArray(); //5、调用DatagramPacket.send()方法发送数据包 DatagramPacket dp=new DatagramPacket(buf, buf.length,new InetSocketAddress("127.0.0.1",5678));//dp端口须Server端口一致 DatagramSocket ds=new DatagramSocket(9999);//Cline端口 ds.send(dp);//发包 ds.close(); } }
