java中的网络编程
一.网络编程概述:基于互联网的编程
就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换.
二.网络模型:OSI和TCP/IP
1.OSI(Open System Interconnection开放系统互连)参考模型
网络模型7层概述:
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之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。
2.TCP/IP参考模型
应用层、传输层、网际层、主机至网络层
三.网络编程三要素:
1.IP地址:
1).所谓IP地址就是给每个连接在Internet上的主机分配的一个32bit地址。
2).按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,比特换算成字节,
就是4个字节。例如一个采用二进制形式的IP地址是“11000000101010000000000101100100”,这么长的地址,
人们处理起来也太费劲了。为了方便人们的使用,IP地址经常被写成十进制的形式,中间使用符号“.”分开不同的字节。于是,
上面的IP地址可以表示为“10.0.0.1”。IP地址的这种表示法叫做“点分十进制表示法”,这显然比1和0容易记忆得多。
例如:192.168.1.10(点分十进制)
二进制表示:11000000.10101000.00000001.00001010
每段使用8位的二进制,一共四段,一共32位表示。
表示范围:
最小IP:00000000.00000000.00000000.00000000
--> 十进制表示:0.0.0.0
最大IP:11111111.11111111.11111111.11111111
--> 十进制表示:255.255.255.255
所以每段的范围:0 -- 255:一共256个。
一共能容纳:256 * 256 * 256 * 256台电脑;
3).IP地址的组成:
IP地址 = 网络号码+主机地址
A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码:192.0.0.0:
范围:192.0.0.0--192.255.255.255:256 * 256 * 256台
B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码:192.168.0.0:
范围:192.168.0.0--192.168.255.255:256 * 256台
C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码:192.168.1.0:
范围:192.168.1.0--192.168.1.255:256台
作用:
以下有三个IP:
1).192.168.1.10;
2).192.168.1.20;
3).192.168.2.30;
上述三个IP地址,能否互相访问?由"子网掩码"来决定:它就是用来区分"网络号码"和"主机地址"的。
如果子网掩码设置为:255.255.255.0
二进制:11111111.11111111.11111111.00000000
子网掩码中,全部标示为1的为"网络号码",上述掩码表示:前三段为"网络号码",前三段相同的IP,表示在一个网段中,可以进行互访;
1)和2)之间可以互访;
如果子网掩码设置为:255.255.0.0
二进制:11111111.11111111.00000000.00000000
上述子网掩码,全部标示为1的为"网络号码",前两段为"网络号码",前两段相同表示在同一网段中,可以进行互访;
1)和2)和3)都可以进行互访;
特殊地址:127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1
DOS命令 ipconfig:查看本机IP地址
xxx.xxx.xxx.0 网络地址
xxx.xxx.xxx.255 广播地址
A类
1.0.0.1---127.255.255.254
(1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)
(2)127.X.X.X是保留地址,用做循环测试用的。
B类
128.0.0.1---191.255.255.254
172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
C类
192.0.0.1---223.255.255.254
192.168.X.X是私有地址
D类
224.0.0.1---239.255.255.254
E类
240.0.0.1---247.255.255.254
2.端口;用于标识进程的逻辑地址,不同进程的标识
1).分类:
物理端口:网卡口;
逻辑端口:是由操作系统维护的。将一个物理端口,映射出多个"逻辑端口",供多个网络程序使用;
2).我们讲的端口,就是"逻辑端口";
3).在Window下,维护65536个逻辑端口,端口号:0 -- 65535
4).一个网络程序要接收网络数据,至少要使用一个端口,而且是"在运行期间独占形式"。一个应用程序可以同时使用多个逻辑端口;
一个端口同时只能为一个程序服务。不能同时被多个程序使用。
5).Windows内部的逻辑端口范围为:0 -- 65535,其中:0--1024是由系统内部使用,我们尽量不要使用;我们尽量使用1024以上的
3.协议;通讯的规则,常见协议:TCP,UDP
1).协议:双方就某些内容达成的约定;目的是使双方都按照约定去做事情;
2).网络编程中的"协议",它所表示:双方发送信息的格式以及对方解析数据的格式;
3).FTP,HTTP,UDP,TCP等等;
4).UDP特点:
1.将发送的数据打包;
2.面向无连接,发送时,不关心对方是否接收。
3.每个数据报的大小在限制在64k;
4.因为不需要连接,所以:不可靠。但速度快;
例如:广播电台,电视台发送信号;
5).TCP特点:
1.发送时,必须建立连接。必须存在接收方,否则不能发送;
2.由于需要建立连接,所以:可靠。但速度(连接速度)会相对慢一些,因为要进行一些连接验证;
例如:打电话
四.InetAdddress类--用来获取IP地址的
1.获取对象:
由于此类没有构造方法,所以可以用其内部静态方法
public static InetAddress getByName(String host):参数:host - 指定的主机,或 null。 返回:给定主机名的 IP 地址。
2.成员方法:
public String getHostName():获取主机名;
public String getHostAddress():获取IP地址
public class Demo {
public static void main(String[] args) {
try {
//获取同一个局域网内的所有主机名
for(int i=0;i<256;i++){
String str="192.168.36."+i;
InetAddress add=InetAddress.getByName(str);//str可以是IP地址啊,也可以是主机名
String name=add.getHostName();
String IP=add.getHostAddress();
System.out.println(name+"---"+IP);
}
} catch (UnknownHostException e) {
}
}
}
五.Socket套接字
1.网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字
2.Socket原理机制:
通信的两端都有Socket。
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO传输。
六.UDP实现
1.发送端:
DatagramSocket socket = new DatagramSocket();
byte[] byteArray = "你好".getBytes();
InetAddress ip = InetAddress.getByName("Lenovo-PC");
int port = 8888;
DatagramPacket pak = new DatagramPacket(byteArray,
byteArray.length,
ip,
port);
socket.send(pak);
socket.close();
2.接收端:
DatagramSocket socket = new DatagramSocket(8888);
byte[] byteArray = new byte[1024];
DatagramPacket pak = new DatagramPacket(byteArray,
byteArray.length);
socket.receive(pak);
byte[] byteArray2 = pak.getData();
String info = new String(byteArray2,0,pak.getLength());
System.out.println("接收到信息:" + info);
socket.close();、
3.发送UDP协议的数据:
步骤:
1.实例化Socket:DatagramSocket对象;DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口。
2.准备发送的信息:
1).发送的信息;
2).目标计算机 的IP;
3).目标计算机的端口;
3.封装一个数据报对象:DatagramPacket对象:构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。length 参数必须小于等于 buf.length。
4.使用Socket发送数据报;socket对象.send(数据包对象)
public class Demo {
public static void main(String[] args) throws Exception{
//发送UDP协议的数据
//创建Datagramsocket对象
DatagramSocket socket=new DatagramSocket();
String str="你好吗 亲爱的";
//创建INetAddress对象
InetAddress adress=InetAddress.getByName("mycomputer");
//声明端口
int port=8888;
//封装数据包对象
DatagramPacket pack=new DatagramPacket(str.getBytes(), str.getBytes().length,adress,port);
//使用socket发送数据包
socket.send(pack);
System.out.println("数据发送完毕");
//释放资源
socket.close();
}
}
4.接收UDP协议数据:
步骤:
1).使用Socket建立连接:DatagramSocket
2).准备一个空的byte[]数组存储接收到的数据。
3).实例化空的数据报对象,等待发送端发送过来的数据;
4).一旦有数据发送过来,解析数据;
public class UDPreceive {
public static void main(String[] args) throws Exception{
//创建Datagramsocket对象,接收数据,使用端口号创建,要使用和发送端相同的端口号
DatagramSocket socket=new DatagramSocket(8888);
//准备空的字节数组,存储数据
byte[] byteArray=new byte[1024];
//利用空的数组,创建空的数据包对象,用来接收数据
DatagramPacket pack=new DatagramPacket(byteArray, byteArray.length);
System.out.println("等待接收数据!!");
//接收数据
socket.receive(pack);程序将在这里阻塞★★★★
System.out.println("接收到数据!!");
//解析数据
//使用字节数组,获取数据包的信息
byte[] byte1=pack.getData();
String str=new String(byte1,0,pack.getLength());//使用数据包的长度,而不是数组的长度
System.out.println(str);
//获取对方的IP和主机名
String IP=pack.getAddress().getHostAddress();★★★//注意此处返回的类型
String name=pack.getAddress().getHostName();
System.out.println("对方IP地址是:"+IP+"对象的主机名称是:"+name);
//释放资源
socket.close();
}
}
5.几个主要的点
pack.getAddress()返回值是InetAddress类型的,可以获得主机的有关信息。
byte[] byte1=pack.getData();可以取出,发来的数据包中的数据进入数组
pack.getLength()返回的是数据包中数据的字节数
接收端(3步)
DatagramSocket socket=new DatagramSocket(8888);对于接收方的socket,要使用端口名来定义
DatagramPacket pack=new DatagramPacket(byteArray, byteArray.length);使用一个空的字节数组定义一个接收端的包
socket.receive(pack);接收数据包。实际上就是讲对象中的数据装入数据包,每次接收都会重新装包,循环时,要不断的装包才可以
发送端(3步)
DatagramSocket socket=new DatagramSocket();使用空参数构造方法,定义发送端的socket
DatagramPacket pack=new DatagramPacket(str.getBytes(), str.getBytes().length,adress,port);使用含有数据的数组,以及数组长度,和目标地址和端口号定义数据包
socket.send(pack);发送数据包。循环时,要不断的创建新包,就必须不断的发送数据包
五.TCP实现:
1.发送端:
Socket socket = new Socket("127.0.0.1",8888);
OutputStream out = socket.getOutputStream();
out.write("你好".getBytes());
out.close();
socket.close();
2.接收端:
ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
InputStream in = socket.getInputStream();
byte[] byteArray = new byte[1024];
int len = in.read(byteArray);
String info = new String(byteArray,0,len);
System.out.println("接收到信息:" + info);
in.close();
socket.close();
server.close();
3.TCP发送数据
步骤:
1).实例化一个Socket对象;使用:目标计算机的IP,端口
2).要发送数据,从Socket对象中,获取一个"输出流";
3).发送数据;
4).释放资源;
注意:TCP是面向连接的,所以必须先启动"接收端"
public class TCPsend {
public static void main(String[] args) throws Exception{
//使用目标主机的IP地址和端口,创建一个socket对象
Socket soc=new Socket("127.0.0.1",8888);
//使用获得socket对象得到一个字节输出流引用
OutputStream out=soc.getOutputStream();
//将数据使用输出流写出
out.write("我们今天要走啦".getBytes());
//关闭资源
out.close();
soc.close();
System.out.println("发送数据完毕");
}
}
4.接收数据:
1.实例化一个ServerSocket:使用端口;
2.等待连接:SeverSocket-->accept();
★★★
3.如果有客户端连接,accept()方法会返回,并返回一个Socket对象,这个Socket对象跟客户端的Socket是
对应的关系;
4.因为客户端先发送数据,这边要先接收数据。从网络读取数据。
获取一个"输入流"。
5.读取数据;
6.释放资源;
public class TCPreceive {
public static void main(String[] args)throws Exception {
//使用端口号,实例化一个Serversocket
ServerSocket server=new ServerSocket(8888);
//等待数据输入
System.out.println("等待客户连接");
//定义一个socket引用,等待客户连接
Socket socket=server.accept();//程序在这里阻塞
System.out.println("有客户连接");
//解析数据
//从得到的socket对象会的一个输入流,从网络获得
InputStream in= socket.getInputStream();
//定义一个字节数组
byte[] byteArray=new byte[1024];
//读取输入流中的数据
int num=in.read(byteArray);
String str=new String(byteArray,0,num);
System.out.println(str);
//释放资源
in.close();
socket.close();
}
}
5.注意:
发送端:(3步)
Socket soc=new Socket("127.0.0.1",8888);//使用目标IP地址和端口名创建对象
OutputStream out=soc.getOutputStream();//使用socket对象创建一个输出流
★★★
out.write("我们今天要走啦".getBytes());//向外写出数据。循环时,要不断的向外写出。
接收端:(4步)
ServerSocket server=new ServerSocket(8888);//使用和发送端口相同的端口创建一个对象
Socket socket=server.accept();程序阻塞等待客户连接,☆★★★★//只是用来等待客户连接
InputStream in= socket.getInputStream();//将socket中的数据读入程序
★★
int num=in.read(byteArray);//将输入流中的数据读出来//循环时,数据不断的经过输入流读入数组,而不需要前面。此时需要不断的刷新