网络编程概述及介绍:
计算机网络:实现资源的共享和传递;网络编程:实现网络互连的不同计算机上运行的程序间可以进行数据交换;
网络参考模拟图:
OSI(开放系统互联)参考模型: TCP/IP参考模型:
应用层
表示层 应用层
会话层
--------------------------------------------------------------
传输层 传输层
--------------------------------------------------------------
网络层 网际层
--------------------------------------------------------------
数据链路层 主机至网络层
物理层
OSI参考模型介绍:
物理层:主要作用,传输比特流(这一层的数据叫做比特);
数据链路层:将物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装(这一层的数据叫做帧);
网络层:从下层接收到的数据进行IP地址的封装与解封装(工作设备:路由器,这一层的数据叫做数据包);
传输层:定义了协议和端口号,主要将从下层接收的数据进行分段和传输,到达目的地后再进行重组(这一层的数据叫做段);
会话层:通过传输层(端口号,传输端口与接收端口)建立数据传输的通道,主要在你的系统之间发起会话或者接收会话请求;
表示层:主要对数据进行解释,加密与解密,压缩与解压缩等;
应用层:主要是一些终端的应用(电脑上可以看到的);
InetAddress:类表示互联网协议(IP)地址;
常用方法:public static InetAddress getByName(String host):在给定主机名(也可以是机器名)的情况下确定主机的 IP 地址;
public String getHostAddress():返回 IP 地址字符串(以文本表现形式);
举例:
public class InetAddRessDemo {
public static void main(String[] args) throws UnknownHostException {
//创建InetAddress对象,通过来获取ip地址
//在知道主机名的情况下
//InetAddress address = InetAddress.getByName("USER-20171205ZR") ;
//IP 地址的文本表示形式
//Ip地址对象
InetAddress address = InetAddress.getByName("DESKTOP-MN4CGJE") ;
//上面获取到了Ip地址
//public String getHostAddress()返回 IP 地址字符串(以文本表现形式)。
String ip = address.getHostAddress() ;
System.out.println(ip); //192.168.10.1
//public String getHostName()获取此 IP 地址的主机名。
String name = address.getHostName() ;
System.out.println(name); //DESKTOP-MN4CGJE
}
}
UDP编程:
特点:1> 不需要建立连接通道;
2> 数据大小有限制;
3> 不可靠连接 ---> 传输速度快;
举例:
发送端:
package org.westos_06;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* 发送端的开发步骤:
* 1)创建发送端的Socket对象
* 2)创建数据,并打包
* 3)调用当前发送端Socket对象中的发送的方法
* 4)关闭资源
*
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
//1)创建发送端的Socket对象
//DatagramSocket:此类表示用来发送和接收数据报包的套接字。
//创建DataGramSocket对象
//构造方法:public DatagramSocket(int port,InetAddress laddr)
//这个构造方法,里面传递并不是Ip地址的文本形式
//构造数据报套接字并将其绑定到本地主机上任何可用的端口
DatagramSocket ds = new DatagramSocket() ;
//2)创建数据,并打包
//DatagramPacket 表示数据报包
//DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
/**
* buf - 包数据。
offset - 包数据偏移量。
length - 包数据长度。
address - 目的地地址。
port - 目的地端口号。
*/
//有数据
byte[] bys = "hello,udp,我来了".getBytes() ;
//获取包数据长度
int len = bys.length ;
//获取ip地址对象
InetAddress address = InetAddress.getByName("192.168.59.1") ;
//指定端口号
int port = 10086 ;
DatagramPacket dp =new DatagramPacket(bys, 0, len, address, port) ;
//3)调用当前发送端Socket对象中的发送的方法send();
/*public void send(DatagramPacket p)
throws IOException从此套接字发送数据报包*/
ds.send(dp);
//4)关闭资源*
ds.close();
}
}
接收端:
package org.westos_06;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
*Udp编程的接收端 开发步骤:
* 1)创建Socket对象
* 2)创建一个数据报包(接收容器)
* 3)调用Socket对象中的接收的方法
* 4)解析实际传递的数据
* 5)将解析的数据(ip,数据)展示在控制台上
* 6)关闭资源
*注意:
*接收端不要运行多次,会出现异常:
* java.net.BindException: Address already in use: Cannot bind
* 绑定异常(地址不能再次被绑定)
*
*
*先运行接收端,再运行发送端;
*/
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//1)创建Socket对象
//public DatagramSocket(int port):创建数据报包套接字对象并且将其绑定到本地主机上的指定端口
DatagramSocket ds = new DatagramSocket(10086);
//2)创建一个数据报包(接收容器)
//public DatagramPacket(byte[] buf, int length)
byte[] bys = new byte[1024] ;
int len = bys.length ;
DatagramPacket dp = new DatagramPacket(bys, len) ;
//3)调用Socket对象中的接收的方法
//public void receive(DatagramPacket p):从此套接字接收数据报包
ds.receive(dp);//阻塞式方法
//获取ip地址文本形式
//public InetAddress getAddress() :返回ip地址对象 数据报包类:DataGramPacket的方法;
InetAddress adress=dp.getAddress();
String ip=adress.getHostAddress();
//getAddress():返回某台机器的 IP 地址,返回类型为:InetAddress;
//getHostAddress():返回 IP 地址字符串(以文本形式表现);
//4)解析实际传递的数据
//public byte[] getData() :获取缓冲中实际数据(从接收容器中获取)
byte[] bys2 = dp.getData() ;
//public int getLength()返回将要发送或接收到的数据的长度。
int len2 = dp.getLength() ;//从接收容器中获取包的实际长度
String data = new String(bys2, 0, len2) ;
System.out.println("当前接收到的数据是:"+data+",来自于"+ip);
//6)关闭资源
ds.close();
}
}
改进接收端和发送端:举例:
发送端:
package org.westos_01;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
*
*将UDP编程的发送端和接收端优化!
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket() ;
//创建数据报包对象
byte[] bys = "hello,udp,我来了".getBytes() ;
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
//构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.0.102"),12345) ;
//发送数据
ds.send(dp);
//释放资源
ds.close();
}
}
接收端:
package org.westos_01;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* DatagramSocket:此类表示用来发送和接收数据报包的套接字。
* DatagramPacket:此类表示数据报包。
*
*/
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//创建接收端的Socket对象
//DatagramSocket(int port):创建数据报套接字并将其绑定到本地主机上的指定端口
DatagramSocket ds = new DatagramSocket(12345) ;
//创建接收容器
//创建字节数组的大小1024或者1024的倍数
byte[] bys = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bys, bys.length);
//调用接收的方法
ds.receive(dp);//阻塞式方法
//java中的阻塞式方法是指在程序调用改方法时,必须等待输入数据可用或者检测到输入结束或者抛出异常,
//否则程序会一直停留在该语句上,不会执行下面的语句;
//解析数据,将数据展示在控制台
//获取ip地址
//getAddress():返回机器的ip地址,返回值类型为:InetAddress
//getHostAddress():返回机器的ip地址,返回值类型为:String
String ip = dp.getAddress().getHostAddress() ;
//public byte[] getData() 获取缓冲区中实际的字节数
//public int getLength() 获取缓冲区中实际的长度
String s = new String(dp.getData(), 0,dp.getLength()) ;
//展示控制台
System.out.println("from"+ip+"data is:"+s);
//释放资源
ds.close();
}
}
完成数据的多次发送和接收:
举例:
package org.westos_02;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* 需求: 将发送端的数据改变方式,并且多次发送
*
*
*/
public class SendDemo {
public static void main(String[] args) {
try {
//创建Socket对象:数据报套接字是包投递服务的发送或接收点
DatagramSocket ds = new DatagramSocket();
//键盘录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null ; //读了一次
while((line=br.readLine())!=null){
//自定义结束条件
if("886".equals(line)) {
break ;
}
byte[] bys = line.getBytes() ;
//创建数据报包
DatagramPacket dp = new DatagramPacket(
bys,bys.length,InetAddress.getByName("192.168.0.102"), 10086);
//发送数据
ds.send(dp);
}
//释放资源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
接收端:
package org.westos_02;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveDemo {
public static void main(String[] args) {
try {
//创建接收端的Socket对象
DatagramSocket ds = new DatagramSocket(10086);
while(true) {
//需要创建接收容器
byte[] bys = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
//接收
ds.receive(dp);
//解析数据
String ip = dp.getAddress().getHostAddress() ;
String s = new String(dp.getData(), 0, dp.getLength()) ;
System.out.println("from" +ip +"data is:"+s);
//释放资源,接收端不停地接收数据,所以不应该该关闭
//ds.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用接口的方式完成数据的多次发送接收:举例:
接收端:
package org.westos_03;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveThread implements Runnable {
private DatagramSocket ds;
public ReceiveThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
while(true) {
//需要创建接收容器
byte[] bys = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
//接收
ds.receive(dp);
//解析数据
String ip = dp.getAddress().getHostAddress() ;
String s = new String(dp.getData(), 0, dp.getLength()) ;
System.out.println("from" +ip +"data is:"+s);
//释放资源,接收端不停地接收数据,所以不应该该关闭
//ds.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
发送端:
package org.westos_03;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SendThread implements Runnable {
private DatagramSocket ds ;
public SendThread(DatagramSocket ds) {
this.ds = ds ;
}
@Override
public void run() {
try {
//使用字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
String line = null ;
//不断发送数据
while((line=br.readLine())!=null) {
//自定义结束条件
if("over".equals(line)) {
break ;
}
byte[] bys = line.getBytes() ;
//创建数据报包
DatagramPacket dp =
new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.0.102"), 10086) ;
//发送数据
ds.send(dp);
}
//释放
ds.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
测试端:
package org.westos_03;
import java.net.DatagramSocket;
/**
** 多线程:
* Runable接口的方式
* SendThread implements Runnable{
* }
* 发送端的线程
* 接收端的线程
*
* 主线程
* 只需要需一个窗口 ,让我们不断发送数据
*
*/
public class ChartRoom {
public static void main(String[] args) throws Exception {
//分别创建发送端和接收端的Socket对象
DatagramSocket sendSocket = new DatagramSocket() ;
DatagramSocket receiveSocket = new DatagramSocket(10086) ;
//创建资源对象
SendThread st = new SendThread(sendSocket) ;
ReceiveThread rt = new ReceiveThread(receiveSocket) ;
//创建线程对象
Thread t1 = new Thread(st) ;
Thread t2 = new Thread(rt) ;
//启动线程
t1.start();
t2.start();
}
}
TCP编程:(建立连接通道);
特点:1> 需要建立连接通道;
2> 数据大小无限制;
3> 可靠连接;
4> 执行效率低;
举例:
服务器端:
package org.westos_04;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
*
*服务端的开发步骤:
* 1)创建服务器端的Socket对象
* 2)监听客户端的连接(阻塞方法)
* 3)获取通道内的输入流
* 4)读取数据,显示控制台
* 5)释放资源
*
*ava.net.BindException: Address already in use: JVM_Bind 地址被绑定,因为已经有服务器在监听客户端连接
*/
public class ServerDemo {
public static void main(String[] args) throws Exception {
//1)创建服务器端的Socket对象
//public ServerSocket(int port) throws IOException创建绑定到特定端口的服务器套接字
ServerSocket ss = new ServerSocket(12306) ;
//2)监听客户端的连接(阻塞方法)
//public Socket accept(): throws IOException侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞
Socket s = ss.accept() ;
//3)获取通道内的输入流
//InputStream getInputStream()
InputStream in = s.getInputStream() ;
//4)读取数据,显示控制台
//获取ip文本形式
//public InetAddress getInetAddress()
String ip = s.getInetAddress().getHostAddress() ;
byte[] bys = new byte[1024] ;
int len = in.read(bys) ;
String data = new String(bys, 0, len) ;
System.out.println("from" +ip +"data is :"+data);
//5)释放资源
s.close();
//ss.close(); 服务端可以不关闭
}
}
客户端:
package org.westos_04;
import java.io.OutputStream;
import java.net.Socket;
/**
*TCP(建立连接通道)编程的客户端的开发步骤
* 1)创建客户端的Socket对象
* Socket:就是客户端的Socket
* 构造方法
* public Socket(InetAddress address, int port)
* public Socket(String host, int port):创建客户端套接字对象,并且指定端口号和ip文本形式
* 2)获取通道内的输出流对象
* 3)给服务器端写数据
* 4)释放资源
*
* java.net.ConnectException: Connection refused: connect 连接被拒绝
*
* 不要先运行客户端,客户端的连接需要服务器监听到才能连接
*/
public class ClientDemo {
public static void main(String[] args) throws Exception {
//1)创建客户端的Socket对象
//public Socket(String host, int port)
Socket s = new Socket("192.168.10.1", 12306) ;
//2)获取通道内的输出流对象
//public OutputStream getOutputStream():获取套接字 的输出流
OutputStream out = s.getOutputStream() ;
//3)给服务器端写数据 过去
out.write("hello,Tcp,我来了".getBytes());
//释放资源
s.close();
}
}