第一章 网络编程
网络 : 连接计算机,共享资源,交换数据等.
1.1 软件结构
C/S
Client/Server ,客户端和服务器端结构 eg:QQ,微信
B/S
Brower/Server,浏览器和服务器端结构 eg:谷歌,火狐
两种架构各有优势,但无论那种架构都离不开网络的支撑
网络编程,就是在一定的协议下,实现两台计算机及的通信的程序
1.2 网络通信协议
1.2.1 概述
为了在网络中不同的计算机之间进行通信而建立的规则,标准,约定的集合.
在计算机网络中,通信双方必须同时遵守才能完成数据的交换
对数据的传递格式,传输的速率,传输的步骤等等都做了统一的规定.
1.2.2 TCP/IP协议
传输控制协议/因特网互联协议,是Internet最基本,最广泛的协议
定义了计算机如何连接到因特网,以及数据如何在它们之间传输的标准,它的内部包含一系列用于处理数据通信的协议,并采用4层分层模型,每一层呼叫它的下一层锁提供的协议来完成自己的需求
- 应用层:是和用户最接近的一层 (eg:HTTP)
- 传输层:向用户提供一些点到点,端到端的服务(TCP,UDP)
- 网络层:实际上就是数据链路【逻辑上的】,比如送某个东西有很多方式可以抵达,网络上称之为路由选择,即在网络层
- 数据链路层:只有电缆还是无法进行通信,在屋里层的基础上各个计算机建立起来的数据链路的连接
- 物理层:电缆,设备
补充:>>> OSI七层模型:
**物理层:**利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
**数据链路层:**负责建立和管理节点间的链路。
**网络层:**通过路由选择算法,为报文或分组通过通信子网选择最适当的路径。
**传输层:**向用户提供可靠的端到端的差错和流量控制,保证报文的正确传输。
**会话层:**向两个实体的表示层提供建立和使用连接的方法。
**表示层:**处理用户信息的表示问题,如编码、数据格式转换和加密解密等。
**应用层:**直接向用户提供服务,完成用户希望在网络上完成的各种工作。
1.2.3 协议分类
1.2.3.1 TCP
传输控制协议(Transmission Control Protocol)
TCP协议是面向连接的通信协议,传输数据之前,在发送和接收端建立逻辑连接,然后传输数据,保证两台计算机之间准确无误的数据传输
在TCP连接中必须要明确客户端和服务器端由客户端向服务器端发出连接请求,每次连接的创建都需要经过"三次握手".
三次握手: TCP协议中,在发送数据的准备阶段,客户端与服务端之间的三次交互,以保证连接的可靠.
完成三次握手,连接建立后,客户端和服务器端就可以进行数据传输了,由于面向连接的特性,TCP协议可以保证传输数据的安全,所以应用比较广泛.
1.2.3.2 UDP
用户数据包协议(User Datagram Prorocol)
UDP是无连接通信协议
简言之,当一台计算机向另一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在接收数据时,也不会向发送端返回是否收到数据的信号
由于使用UDP消耗资源小,通信效率高,所以通常音频,视频和普通数据的传输,eg:视频会议都是用UDP协议,因为这种场景偶尔丢失一两个数据包,也不会对接收数据产生太大的影响.
但是在使用UDP传输数据时,由于UDP的面向无连接,不能保证数据的完整,因此在传输重要数据时不建议使用UDP协议.
特点 : 数据被限制在64kb以内,超出该范围就不能发送了.
1.2.3.3 TCP与UDP的区别:
**TCP:**传输控制协议(Transmission Control Protocol),是面向连接的通信协议.
优点: 因为是面向连接的传输,端口和端口进行匹配,所以数据传输比较稳定,以字节的形式传输数据.
缺点: 因为连接是需要”三次握手”,所以传输的速度较慢
UDP:(UserDatagram Protocol)是一种无连接的协议,每个数据包都是独立的
优点: 传输速率快,效率高
缺点: 数据容易丢失
1.3 网络编程三要素
1.3.1 协议
计算机网络通信必须遵守的规则.
1.3.2 IP地址
互联网协议地址,IP就是用来给网络中的计算机设备做唯一编号
1.3.2.1 IP的分类
IPv4 :是一个32位的二进制数,通常分为4个字节,表示成a.b.c.d
eg : 192.168.20.79
a,b,c,d分别都是0~255之间的十进制整数,最多可以表示42亿个.
IPv6:由于互联网的发展,IP地址的需求量增大,但是网络地址资源有限,为了扩展,采用v6,采用了128位地址长度,没16个字节为一组,分为8组的十六进制 ,表示为: 1234:5678:ABCD:EF01: 1234:5678:ABCD:EF01,可以给世界上每一粒沙子进行编地址,解决了IP匮乏的问题.
1.3.2.2 常用命令
查看本机的IP地址, 输入:
ipconfi
查看网络是否连接, 输入:
ping IP地址
1.3.3 端口号
网络的通信
本质上就是两个进程(应用程序)之间的通信,每台计算机上都有很多进程.
区分各个进程 : 端口号
![在这里插入图片描述](https://img-blog.csdnimg.cn/a5c9176c52e94afe9a5b89e5354071ff.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5p-SMDAwNw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center
1.4 DNS域名解析
访问网站时,为什么输入的是网址而不是IP地址?
因为域名好记,并且域名可以通过DNS解析成IP
DNS : Donmain Name System,域名系统
1.5 网络服务器
通常在网络环境下,具有较高的计算能力,能够提供用户服务的计算机
eg : Tomcat (http协议 : 简单的文本传输协议)
第二章 TCP通信程序
2.1 TCP基本概念
Java中提供了两个类用于TCP通信程序
客户端:
java.net.Socket -> 客户端套接字
套接字:包含了IP地址和端口号的网络单位
构造方法:
Socket(String host,int port)
参数: String host :服务器主机名称、服务器的IP地址 eg: 192.168.8.132 / 127.0.0.1 / localhost
int port :服务器的端口号
成员方法:
getOutputStream()
getIntputStream()
close()
实现步骤:
1.创建客户端对象 >>new Socket()
2.使用socket对象中的getOutputStream()
3.使用字节输出流中的write()方法发送数据
package com.company.project09.Test03;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.创建socket
Socket socket = new Socket("192.168.8.132",8888);
//2.getOutputStream()
OutputStream outputStream = socket.getOutputStream();
//3.write()
outputStream.write("你好".getBytes());
//4.释放
socket.close();
}
}
服务端:
java.net.ServerSocket ->服务器套接字
构造方法:
ServerSocket(int port)
方法:
Socket accept(); 侦听要连接的客户端
实现步骤:
1.创建服务器对象 >>new ServerSocket()
2.侦听客户端 >>accept()
3.使用scoket对象中的getInputStream读取客户端发送的数据
4.创建一个容器,来接收数据 >>new byte[]
5.读取数据 >>read()
package com.company.project09.Test03;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.创建socket
Socket socket = new Socket("192.168.8.132",8888);
//2.getOutputStream()
OutputStream outputStream = socket.getOutputStream();
//3.write()
outputStream.write("你好".getBytes());
//4.释放
socket.close();
}
}
注意: 运行时,必须先运行服务器端,再运行客户端.
看完这么多,想必大家多少有点收获吧,那就检测一下,加深印象吧!
小练习:利用io流,将一个文件“复制”到另外的路径下,具体操作如下图所示。
package com.company.project09.Test04;
import java.io.*;
import java.net.Socket;
public class TcpClient {
public static void main(String[] args) throws IOException {
/* 1.将文件从磁盘中读取到客户端 */
//创建文件输入字节流
InputStream inputStream = new FileInputStream("E:\\file/a.png");
//创建一个容器
byte[] bytes = new byte[1024];
//使用read()方法读
int len = inputStream.read(bytes);
/* 2.将读取进来的(字节)写入服务器端 */
//创建客户端对象
Socket socket = new Socket("192.168.8.132", 8888);
//使用getOutputStream()
OutputStream outputStream1 = socket.getOutputStream();
//write();
outputStream1.write(bytes);
//使用getInputStream()
InputStream input = socket.getInputStream();
//新容器
byte[] bytes1 = new byte[1024];
//read()读
// int lenNew = input.read(bytes1);
/* 5.将从服务器端读进的字节写入指定路径的文件夹中 */
//创建文件输出字符流对象
OutputStream outputStream = new FileOutputStream("E:\\fileNew/a.png");
int lenNew = 0;
while((lenNew = input.read(bytes1)) != -1){
outputStream.write(bytes1);
}
//释放
inputStream.close();
outputStream.close();
}
}
package com.company.project09.Test04;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws IOException {
/* 3.将客户端的字节读进服务器端 */
//创建一个ServerSocket对象
ServerSocket serverSocket = new ServerSocket(8888);
//侦听客户端对象
Socket socket = serverSocket.accept();
//使用getInputStream()
InputStream in = socket.getInputStream();
//创建一个接收的容器
byte[] bytes = new byte[1024];
// //使用read()读
// int len1 = in.read(bytes);
/* 4.再讲读进来的字节写到客户端 */
//使用getOutputStream()
OutputStream out = socket.getOutputStream();
//边读边写
int len = 0;
while ((len = in.read(bytes)) != -1){
out.write(bytes);
}
//释放
in.close();
out.close();
}
}
2.2 URL统一资源定位符
-
URL(Uniform Resource Locator)
统一资源定位符,由4个部分组成: 协议 , 存放资源的主机域名, 端口号 和 资源文件名
-
URL是指向互联网"资源"的指针.
资源可以是简单的文件或目录,也可以是对很为复杂的对象的引用,例如:对数据库或搜索引擎的 查询.
-
2.3 Socket 套接字
我们开发的网络应用程序位于应用层,TCP和UDP属于传输层协议,在应用层和传输层之间,则是使用套接字来进行分离的.
套接字就像传输层为应用层开的小口,应用层通过这个小口像远程发送数据,或接收远程发送来的数据;而这个小口以内,也就是数据进入到这个小口之后,或者数据从这个小口出来之前,是不知道也不需要知道的,也不会关心它如何传输,这属于网络其他层次的工作.
Socket实际是传输层给应用层的编程接口.传输层则在网络层的基础上提供进程到进程间的逻辑通道,而应用层的进程则利用传输层向另一台主机的某一程序进程通信. Socket就是应用层和传输层之间的桥梁
使用Socket编程可以开发客户机和服务器应用程序,可以在本地网络上进行通信,也可以通过Internet在全球范围内通信.
Socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。正如打电话之前,双方必须各自拥有一台电话机一样。
套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
第三章 UDP通信程序
3.1 UDP基本概念
DatagramSocket : 用于发送或接收数据包
DatagramPackage : 数据包
构造:
DatagramSocket(port)
DatagramPacket(buf,buf.length,address,port)
DatagramPacket(buf,buf.length)
方法:
send(packet)发送一个数据包
receive(packet)接收一个数据包
getData()获得数据包的字节数组
getLength()获取数据的长度
getAddress()获取对方的IP地址
getPort()获取对方接收数据的端口
3.1.1一次单向通信:
所谓单向通信,就是只能由一方给另一方输入消息,而不能收到来自另一方的消息。相当于只能有一端进行发送消息,另一端只能接收,而不能进行发送。【代码如下】
客户端:
package com.company.project09.Test07;
import java.io.IOException;
import java.net.*;
/**
* 客户端
*/
public class UDPClient {
public static void main(String[] args) throws IOException {
//1.创建一个Socket,用来发送和接收数据包
DatagramSocket socket = new DatagramSocket(9999);//服务端返回数据给客户端,客户端采用9999这个端口来接收数据
//2.使用一个Socket,发送数据包
String str = "亲,在吗";
byte[] buf = str.getBytes(); //将字符串转化为一个字节数组
InetAddress address = InetAddress.getLocalHost();
int port = 8888; //端口号 >>发送给谁
DatagramPacket packet = new DatagramPacket(buf,buf.length,address,port);//发送字节数组,字节长度,发送位置(服务器端地址),发送位置的端口号
socket.send(packet);//发送数据
//3.关闭数据包>>Socket
socket.close();
}
}
服务器端:
package com.company.project09.Test07;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* 服务器端
*
* 迭代1 : 一次单项通信(单向)
*/
public class UDPServer {
public static void main(String[] args) throws IOException {
//1.创建一个Socket,用来发送和接收数据包
DatagramSocket socket = new DatagramSocket(8888);
//2.使用Socket接收数据包并输出
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);//接收数据
System.out.println(new String(packet.getData()));//将字节数组转化为字符串
System.out.println(packet.getData());
System.out.println(packet.getLength());
System.out.println(packet.getAddress());
System.out.println(packet.getPort());
//3.关闭数据包>>Socket
socket.close();
}
}
3.1.2双向的通信:
双向通信顾名思义,就是两端都可以进行信息的发送和接收,相当于一个建议的聊天室。
客户端:
package com.company.project09.Test09;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* 客户端
*/
public class UDPClient {
public static void main(String[] args) throws IOException {
//1.创建一个Socket,用来发送和接收数据包
DatagramSocket socket = new DatagramSocket(9999);//服务端返回数据给客户端,客户端采用9999这个端口来接收数据
//2.使用一个Socket,发送数据包
String str = "亲,在吗";
byte[] buf = str.getBytes(); //将字符串转化为一个字节数组
InetAddress address = InetAddress.getLocalHost();
int port = 8888; //端口号 >>发送给谁
DatagramPacket packet = new DatagramPacket(buf,buf.length,address,port);//发送字节数组,字节长度,发送位置(服务器端地址),发送位置的端口号
socket.send(packet);//发送数据
//3.接收服务器端的反馈
byte[] buf2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(buf2,buf2.length);
socket.receive(packet2);
System.out.println(new String(packet2.getData(),0,packet2.getLength()));
System.out.println(packet2.getData());
System.out.println(packet2.getLength());
System.out.println(packet2.getAddress());
System.out.println(packet2.getPort());
//4.关闭数据包>>Socket
socket.close();
}
}
服务器端:
package com.company.project09.Test09;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* 服务器端
*
* 迭代2 : 双向通信
*/
public class UDPServer {
public static void main(String[] args) throws IOException {
//1.创建一个Socket,用来发送和接收数据包
DatagramSocket socket = new DatagramSocket(8888);
//2.使用Socket接收数据包并输出
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);//接收数据
System.out.println(new String(packet.getData(),0,packet.getLength()));//将字节数组转化为字符串
System.out.println(packet.getData());
System.out.println(packet.getLength());
System.out.println(packet.getAddress()); //获取对方的IP地址
System.out.println(packet.getPort());//获取对方的端口号
//3.使用Socket发送一个响应
String str = "欧,在呢在呢";
byte[] buf1 = str.getBytes();
DatagramPacket pecket1 = new DatagramPacket(buf1,buf1.length,packet.getAddress(),packet.getPort());//注:发送参数多>>4个
socket.send(pecket1);
//4.关闭数据包>>Socket
socket.close();
}
}
3.1.3循环双向:
客户端:
package com.company.project09.Test10;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/**
* 客户端
*/
public class UDPClient {
public static void main(String[] args) throws IOException {
//1.创建一个Socket,用来发送和接收数据包
DatagramSocket socket = new DatagramSocket(9999);//服务端返回数据给客户端,客户端采用9999这个端口来接收数据
//** 接收来自键盘的输入
Scanner sc = new Scanner(System.in);
while(true){
//2.使用一个Socket,发送数据包
System.out.println("请您发送消息..");
String str = sc.nextLine();
byte[] buf = str.getBytes(); //将字符串转化为一个字节数组
InetAddress address = InetAddress.getLocalHost();
int port = 8888; //端口号 >>发送给谁
DatagramPacket packet = new DatagramPacket(buf,buf.length,address,port);//发送字节数组,字节长度,发送位置(服务器端地址),发送位置的端口号
socket.send(packet);//发送数据
//如果客户端输入 bye ,则结束会话
if("bye".equals(str)){
break;
}
//3.接收服务器端的反馈
byte[] buf2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(buf2,buf2.length);
socket.receive(packet2);
System.out.println(new String(packet2.getData(),0,packet2.getLength()));
}
//4.关闭数据包>>Socket
socket.close();
}
}
服务器端:
package com.company.project09.Test10;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Scanner;
/**
* 服务器端
*
* 迭代2 : 双向通信
*/
public class UDPServer {
public static void main(String[] args) throws IOException {
//1.创建一个Socket,用来发送和接收数据包
DatagramSocket socket = new DatagramSocket(8888);
Scanner sc = new Scanner(System.in);
while(true){
//2.使用Socket接收数据包并输出
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);//接收数据
String string = new String(packet.getData(),0,packet.getLength());
if ("bye".equals(string)){
break;
}
//3.使用Socket发送一个响应
System.out.println("请尽快回复客户消息..");
String str = sc.nextLine();
byte[] buf1 = str.getBytes();
DatagramPacket pecket1 = new DatagramPacket(buf1,buf1.length,packet.getAddress(),packet.getPort());//注:发送参数多>>4个
socket.send(pecket1);
}
//4.关闭数据包>>Socket
socket.close();
}
}
第四章:测试
测试分类:
白盒测试: 利用代码进行程序测试
黑盒测试: 不知道测试的代码内容,进行测试
注解:
@Test 测试
@Before 在程序运行前,必须执行的内容
);//接收数据
String string = new String(packet.getData(),0,packet.getLength());
if (“bye”.equals(string)){
break;
}
//3.使用Socket发送一个响应
System.out.println("请尽快回复客户消息..");
String str = sc.nextLine();
byte[] buf1 = str.getBytes();
DatagramPacket pecket1 = new DatagramPacket(buf1,buf1.length,packet.getAddress(),packet.getPort());//注:发送参数多>>4个
socket.send(pecket1);
}
//4.关闭数据包>>Socket
socket.close();
}
}
# 第四章:测试
测试分类:
白盒测试: 利用代码进行程序测试
黑盒测试: 不知道测试的代码内容,进行测试
**注解:**
@Test 测试
@Before 在程序运行前,必须执行的内容
@After 在程序运行之后才能执行的内容