概述:
1,找到对方IP
2,数据要发送到对方指定的应用程序上,为了标识这些应用程序,给网络应用程序添加数字标识,这个数字就称之为端口
3,定义通信规则,这个通讯规则就称为协议,国际通用的协议为TCP/IP
网络模型
OSI参考模型、TCP/IP参考模型
1.物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特
2.数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输
3.网络层:主要将下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。
4.传输层:定义了一些传输数据的协议和端口号(WWW端口号80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层叫做段。
5.会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接收会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)
6.表示层:主要是进行对接收的数据进行解释,加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够识别的东西(如图片、声音等)。
7.应用层:主要是一些终端的应用,比如说FTP(各种文件下载)、WEB(IE浏览)、QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西,就是终端应用)。
网络通讯要素
IP地址:InetAddress
网络中设备的标识;不易记忆,可用主机名;本地回环地址:127.0.0.1 主机名:localhost
端口号
用于标识进程的逻辑地址,不同进程的标识;有效端口:0~65535,其中0~1024系统使用或保留端口。
传输协议
通讯的规则;常见协议:TCP,UDP,二者区别如下表:
UDP特点 | TCP特点 |
将数据及源和目的封装成数据包中,不需要建立连接 | 建立连接,形成传输数据的通道。 |
每个数据报的大小在限制在64k内,封包 | 在连接中进行大数据量传输 |
因无连接,是不可靠协议 | 通过三次握手完成连接,是可靠协议 |
不需要建立连接,速度快 | 必须建立连接,效率会稍低 |
Socket
Socket就是为网络服务提供的一种机制。
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。
192.168.1.0网络段
192.168.1.255广播段,给在网段内的所有端口发布广播
UDP传输
DatagramSocket与DatagramPacket
1,建立发送端,接收端。
2,建立数据包。
3,调用Socket的发送接收方法。
4,关闭Socket。
发送端与接收端是两个独立的运行程序。
发送端
需求: 通过UDP传输,将一段文字发送出去
思路:
1,建立Udpsocked服务,通过DatagramSocked对象
2,提供数据,并将数据封装到数据包中;方法:DatagramPacket(byte[] buf, int length, InetAddress address, int port)
3,通过socked服务的发送功能,将数据发送出去
4,关闭资源
import java.net.*; class UdpSend //发送端 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(1234);//1,创建服务 byte[] buf = "UDP is coming".getBytes();//2,构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。 DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.254"),10000); ds.send(dp); //3,通过socket服务发送数据包 ds.close(); //4, } }
接收端:
需求:定义一个应用程序,接收UDP协议传输的数据并处理
思路:
1,定义Udpsocket服务,建立接收端点;监听风端口数字标识;方便于明确哪些数据需要该应用程序接收处理
2,定义一个数据包,用来存储接收到的字节数据;数据包对象中有更多功能可以提取字节数据的不同数据信息
3,通过socket服务的receive方法将接收到的数据存入已经定义好的数据包中
4,通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上
5,关闭资源
class UdpReceive //接收端 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(10000);//1,创建接收端点,监听吧指定端口 while(true) { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length);//2,定义存储数据的数据包 ds.receive(dp); //3、通过receive方法将接收到的数据存入数据包中 //线程阻塞式方法,会抛出IO异常 String ip = dp.getAddress().getHostAddress();//4、通过数据包方法获取其中数据 String data = new String(dp.getData(),0,dp.getLength());//数据 int port = dp.getPort(); //端口号 System.out.println(ip+" : "+data+" : "+port); // ds.close(); //5、关闭资源 } } }
通过键盘录入完成UDP的发送和接收
import java.net.*; import java.io.*; class UdpSend2 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(); //创建发送端 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//键盘录入 String line = null; while ((line=bufr.readLine()) !=null)//阻塞式方法read { if("886".equals(line)) break; byte[] buf = line.getBytes();//字节数组 封包 DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10086); ds.send(dp); //发送 } ds.close(); } } class UdpRec { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(10086); //创建接收端 while (true) { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length);//将接收的数据封包 ds.receive(dp);//阻塞式方法 String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); System.out.println(ip+" : "+data); } } }
通过UDP和多线程和IO的聊天程序
需求:编写一个聊天程序
分为数据发送和数据接收两部分,两部分需要同时在一个进程执行,用到多线程;两个线程分别控制发送和接收
收和发动作不一致,所以要定义两个run方法在两个不同的类中
import java.net.*; import java.io.*; class Send implements Runnable { private DatagramSocket ds; public Send(DatagramSocket ds){ this.ds = ds; } public void run() { try{ BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; while ((line=bufr.readLine()) !=null) { if("886".equals(line)) break; byte[] buf = line.getBytes(); //192.168.1.255广播段,给在网段内的所有端口发布广播 DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10011); ds.send(dp); } } catch (Exception e){ throw new RuntimeException("发送失败!"); } } } class Rece implements Runnable { private DatagramSocket ds; public Rece(DatagramSocket ds){ this.ds = ds; } public void run() { try{ while (true) { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); ds.receive(dp); String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); System.out.println(ip+":"+data); } } catch (Exception e){ throw new RuntimeException("接收失败!"); } } } class UdpTest { public static void main(String[] args) throws Exception { DatagramSocket sendSocket = new DatagramSocket(); DatagramSocket receSocket = new DatagramSocket(10011); new Thread(new Send(sendSocket)).start(); new Thread(new Rece(receSocket)).start(); } }