网络
网络编程
计算机网络
概念:计算机网络是将不同的地理区域的具有独立功能的计算机,通过通信线路连接起来,由功能完善的软件实现资源共享和信息传递的系统。
网络编程概述
概念:通过计算机语言设计软件,使用软件在网络上进行数据的交换
目的:直接或间接地通过网络协议与其他计算机进行通讯
网络编程中有两个主要的问题:
如何准确地定位网络上一台或多台主机 找到主机后如何可靠高效地进行数据传输
java中的网络编程
java在语言级上提供了提供了对网络应用程序的支持,使得java程序员能够很容易开发常见的网络应用程序,java在ava提供的网络类库,可以实现网络连接,联网的底层细节被隐藏在Java 的本机安装系统里,由 JVM 进行控制。并且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
Java将支持网络编程的类都封装在了java.net包下,提供了支持TCP/UDP传输的实现类
网络模型
OSI模型 分为七层,是理想参考模型
TCP/IP模型 分为四层,是实际实现的模型
网络的通信要素
IP地址
IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址.网络中的计算机使用IP地址来进行唯一标识
在Windows系统下,打开cmd,输入命令ipconfig,按回车即可查看。
其中本地回环地址(hostAddress):127.0.0.1 ,它代表设备的本地虚拟接口.
端口号
端口号是计算机程序中的一个整数数字标号,用来区分不同的应用程序
0 ~ 1024 未被系统使用或保留的端口号,0 ~ 65535为有效的端口号,也就是说我们要对一些程序定义端口号的时候,要选择1024 ~ 65535范围内的整数数字。常见的端口号有例如MySql:3306,SQLServer:1433, Oracle:1521,使用IP地址与端口号就可以定位网络上某一台主机上的某个程序
协议
网络通信协议:计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代码结构、 传输控制步骤、出错控制等制定标准。
在学习java的过程中必须要了解传输层(运输层)的两个协议:传输控制协议TCP(Transmission Control Protocol)与用户数据报协议UDP(User Datagram Protocol)
TCP协议
使用协议前必须采用”三次握手“的方式去建立连接,形成传输数据通道,是安全可靠的
TCP协议进行通信的两个应用进程:客户端、服务端
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低
在断开时要进行“四次挥手”
UDP协议
将数据,源(ip地址),目的封装成数据包(报),无需要建立连接
每个数据报的大小限制在64K内
因无需连接,故是不可靠的
发送数据结束时无需释放资源,速度快
TCP编程
利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实上的标准
● 通信的两端即客户端与服务器端都要有Socket,是两台机器间通信的端点
● 网络通信其实就是Socket间的通信
● Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
客户端Socket的工作过程:
● 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务 器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
● 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流, 使用 getOutputStream()方法获得输出流,进行数据传输
● 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的 信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。
● 关闭 Socket:断开客户端到服务器的连接,释放线路
Socket类的构造方法:
Socket(String host,int port)throwsUnknownHostException,IOException:
向服务器(域名是host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。 Socket(InetAddress address,int port)throws IOException:
根据InetAddress对象所表示的IP地址以及端口号port发起连接。
通信套接字Socket类对象在客户端创建的时候会自动向服务器方发起连接
public class Client {
public static void main(String[] args) throws IOException {//为方便测试在main方法中抛出异常,下面测试做法相同
Socket socket=new Socket("127.0.0.1",9999);//在创建Socket类对象的时候会自动连接服务器端,检查服务器端是否开启
//如果服务器端未启动则会抛出异常 java.net.ConnectException: Connection refused: connect
OutputStream out= socket.getOutputStream();//通过socket对象获取一个输出流SocketOutputStream类的对象
out.write("你好服务器端".getBytes("utf-8"));
}
}
服务器端的工作过程:
● 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端 口上。用于监听客户端的请求。
● 调用 accept():监听连接请求,进入阻塞状态,如果客户端请求连接,则接受连接,返回通信 套接字(Socket)对象。
● 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取 输出流和输入流,开始网络数据的发送和接收。
● 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
public class Server {
public static void main(String[] args) throws IOException {
try {
ServerSocket ss = new ServerSocket(9999);//构造方法会抛出异常,防止端口号出现不正常的情况
//java.net.BindException: Address already in use: JVM_Bind,端口号已被占用的异常
System.out.println("服务器连接中,请稍后");
//建立客户端监听
Socket socket = ss.accept();//监听客户端连接,该监听是阻塞式的,没有客户端连接代码就不会继续执行
System.out.println("客户端连接成功");
InputStream in = socket.getInputStream();//通过接收到的客户端对象获取一个输入流ScoketInputStream类的对象
byte[] b = new byte[50];
int size = in.read(b);
String s = new String(b, 0, size, "utf-8");//通过String类的构造方法将接收到的byte数组转换为字符串
System.out.println("客户端说:" + s);
}catch(BindException bindException){
bindException.printStackTrace();
System.out.println("端口号被占用");
}
ss.close();
socket.close();//关闭通信套接字
}
}
使用Socket对象的流时可以引入DataOutputStream类与DataInputStream类,这是两个处理流,这两个流可以帮助我们将字符串与字节相互转换,其中的writeUTF(),readUTF()方法可以直接读取字符串,省去了手动转换的流程
DataOutputStream dos=new DataOutputStream(socket.getOutputStream());
dos.writeUTF(info);
DataInputStream dis=new DataInputStream(socket.getInputStream());
String serverInfo = dis.readUTF();
若是使用Socket对象传输文件,则在文件传输完成的时候需要使用shutdownOutput()方法告诉服务器端,文件传输完成了
UDP编程
返送端接收端的工作流程:
-
在两端都要创建DatagramSocket类与DatagramPacket类对象
-
建立数据报对象,将传输的数据,数据长度,IP地址,端口号封装成数据报对象
-
调用DatagramSocket的方法send()发送数据报对象、receive()进入阻塞状态接收数据报对象后才继续执行
-
关闭Socket对象
发送端代码演示:
public class Send {
public static void main(String[] args) throws IOException {
//UDP协议中发送端的任务只有发送数据报,发送成功与否发送端是无法得知的
//创建套接字对象
DatagramSocket datagramSocket=new DatagramSocket();
byte [] b="你好接收端".getBytes();
//建立数据报
DatagramPacket datagramPacket=new DatagramPacket(b,0,b.length,InetAddress.getByName("127.0.0.1"),9999);
//发送数据报
datagramSocket.send(datagramPacket);//调用send方法将数据报发出
datagramSocket.close();//关闭套接字对象
}
}
接收端代码演示:
public class Receive {
public static void main(String[] args) throws IOException {
//创建套接字对象
DatagramSocket datagramSocket=new DatagramSocket(9999);//创建DatagramSocket类对象,指定监听的端口号
byte[] b=new byte[1024];//创建接收的数组
DatagramPacket datagramPacket=new DatagramPacket(b,b.length);
//接收发送端发送的数据报
datagramSocket.receive(datagramPacket);//进入阻塞状态,知道接收到数据报之后再执行后面的代码
String info=new String(datagramPacket.getData(),0,datagramPacket.getLength());
System.out.println(info);
datagramSocket.close();//关闭套接字对象
}
}