目录放在这里太长了,附目录链接大家可以自由选择查看——–Java学习目录 服务器端 接收方
目录,更新ing,学习Java的点滴记录
一丶网络编程入门
1. 软件结构
网络编程
,就是在一定的协议下,实现两台计算机的通信的程序.2.网络通信协议
1) 应用层(Application Layer):应用层包含所有的高层协议,包括:虚拟终端协议(TELNET),文件传输协议(FTP,File Transfer Protocol),电子邮件传输协议(SMTP,Simple Mail Transfer Protocol),域名服务(DNS,Domain Name Service),网上新闻传输协议(NNTP,NET News Transfer Protocol)和超文本传送协议(HTTP,HyperText Transfer Protocol)
等
2) 传输层(Transport Layer):使源端和目的端机器上的对等实体进行通信.在这一层定义了两个端到端的协议:传输控制协议(TCP,Transmission Control Protocol)和用户数据报协议(UDP,User Datagram Protocol)
。TCP是面向连接的
协议,它提供可靠的报文传输和对上层应用的连接服务。为此,除了基本的数据传输外,它还有可靠性保证,流量控制,多路复用,优先权和安全性控制等功能。UDP是面向无连接
的不可靠传输协议,主要用于不需要TCP的排序和流量控制等功能的应用程序。
3) 网络层(Internet Layer):网络层是整个体系结构的关键部分,其功能是使主机可以把传输数据进行分组,然后将分组发送往任何网络,并使分组独立地传向目标,这些分组可能经由不同的网络,到达的顺序和发送的顺序也可能不同.高层如果需要顺序手法,那么就必须自行处理对分组的排序.
4) 链路层(Link Layer):用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤,网线提供的驱动3.通信协议分类
java.net
包中包含的类和接口,它们提供低层次的通信细节。我们可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。
java.net
包中提供了两种常见的网络协议的支持:
1) UDP:用户数据报协议(User Datagram Protocol)。UDP是无连接
通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在
,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据
。由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议
都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性
,因此在传输重要数据时不建议使用UDP协议
。UDP的交换过程如下图所示。
特点:数据被限制在64kb以内,超出这个范围就不能发送了。
数据报(Datagram):网络传输的基本单位
2) TCP:传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错
的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手"",每次断开连接都要"四次挥手".”
A. 三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
A.1 第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由syn=1知道,A要求联机
A.2 第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机的seq+1),syn=1,ack=1,随机产生的seq=7654321的数据包
A.3 第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1,则连接成功
完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛,例如下载文件、浏览网页等。
B. 四次挥手:由于TCP的半关闭造成的
.因为TCP连接是全双工的(即数据可以在两个方向上同时传递),所以进行关闭时每个方向上都要单独进行关闭.这个单方向的关闭就叫做半关闭.当一方完成它的数据发送任务,就发送一个FIN来向另一方通告将要终止这个方向的连接.
B.1 :第一次挥手:客户机A把连接释放报文段首部的FIN(终止位)置1,其序号seq=u,序号位等于前面已传送过的数据的最后一个字节的序号+1。这个时候,A进入了FIN-WAIT-1(终止等待1)状态,等待B的确认。
B.2 :第二次挥手:服务器B收到连接释放报文段后,同样会返回一个确认报文段。确认号是ack = u+1,而这个报文段自己的序号是v,等于B前面已传送过的数据的最后一个字节的序号加1。发送完确认报文段后,服务器B就会进入CLOSE-WAIT(关闭等待)状态。TCP服务器进程这时应通知高层应用进程,因此从A到B这个方向的连接就释放了。但是此时TCP连接尚未完全关闭,仍处于一个半关闭(half-close)状态。简单地说,此时,客户机A已经没有数据要发送给服务器B了,但是B若发送数据,A仍要接收数据。这个状态可能会持续一段时间。客户机A收到来自服务器B的确认报文段后,就会进入FIN-WAIT-2(终止等待2)状态,等待来自服务器B的连接释放报文段.
B.3 :第三次挥手:服务器B发出连接释放报文段是FIN置1。我们先假设B现在的序号为w,确认号则为上次已发送过的确认号ack = u+1。然后B就LAST-ACK(最后确认)状态,等待A的确认。
B.4 :第四次挥手:客户机A收到B的连接释放报文段后,需要返回确认报文段。在确认报文段中,把ACK置1,确认号为ack = w + 1。而自己的序号为seq = u+1。(根据TCP标准,前面发送过的FIN报文段需要消耗一个序号)。然后进入TIME-WAIT(时间等待)状态。注意,这个时候TCP连接还未结束,还需要时间等待计数器(TIME-WAIT timer)设置的时间2MSL后,A才会重新进入CLOSED状态。时间MSL叫做最长报文段寿命,1MSL大概为2分钟。当A撤销相应的传输控制块TCB后,就结束了这次的TCP连接。
4.网络编程三要素
协议
+IP地址
+端口号
三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。
1) 概念:IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设备做唯一的编号。假如我们把“个人电脑”比作“一台电话”的话,那么“IP地址”就相当于“电话号码”。
2) 分类:
a.IPv4:是一个32位的二进制数,通常被分为4个字节,表示成a.b.c.d
的形式,例如192.168.65.100
。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个.
b.IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题
3) 常用命令:
a. 控制台输入ipconfig,可以查看本机IP地址
b. 检查网络是否连通:ping 目标IP地址,如果显示能够成功接收数据,说明本机和目标IP地址之间可以通信
4) 特殊IP地址:
本机IP地址:127.0.0.1
、localhost
。
5) IP地址=网络ID+主机ID
网络ID:标识计算机或网络设备所有的网段
主机ID:标识特定的主机或网络设备
1) 网络的通信,本质上是两个进程(应用程序)的通信。每台计算机都有很多的进程,那么在网络通信时,如何区分这些进程呢?
2) 如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的进程(应用程序)了。
3) 概念:**端口号:用两个字节表示的整数,它的取值范围是065535**。其中,01023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
4) 常见端口号:网络端口(80),MySQL数据库端口(3306),Oracle数据库端口(1521),tomcat(8080)二丶TCP通信程序
1. 概述
客户端(Client)与服务端(Server
)。
1) 服务端程序,需要事先启动,等待客户端的连接。
2) 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。
1) 客户端:java.net.Socket
类表示。创建Socket
对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。
2) 服务端:java.net.ServerSocket
类表示。创建ServerSocket
对象,相当于开启一个服务,并等待客户端的连接。
1) 多个客户端和服务器进行交互,服务器必须明确在特定时间是和哪个客户端进行交互—在服务器端有个方法交accept(),可以获取到请求的客户端对象,根据对象可以判断此时是哪个客户端在与服务器端进行交互
2) 多个客户端同时和服务器进行交互,就需要使用多个IO流对象
a. 服务器端是没有IO流的,但是服务器可以获取到发出请求的客户端对象Socket
b. 使用每个客户端Socket中提供了IO和客户端进行交互,服务器使用客户端的字节输入流读取客户端发送的数据,并使用客户端的字节输出流给客户端返回数据2. Socket类
Socket
类:该类实现客户端套接字,是计算机之间通信的一种约定或一种方式,通过Socket这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据.
public Socket(String host, int port)
:创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为回送地址。
回送地址(127.x.x.x) 是本机回送地址(Loopback Address),主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,立即返回,不进行任何网络传输。
如:Socket client = new Socket(“127.0.0.1”, 6666);
1) public InputStream getInputStream()
: 返回此套接字的输入流。
如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。
关闭生成的InputStream也将关闭相关的Socket。
2) public OutputStream getOutputStream()
: 返回此套接字的输出流。
如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。
关闭生成的OutputStream也将关闭相关的Socket。
3) public void close()
:关闭此套接字。
一旦一个socket被关闭,它不可再使用。
关闭此socket也将关闭相关的InputStream和OutputStream 。
4) public void shutdownOutput()
: 禁用此套接字的输出流。
任何先前写出的数据将被发送,随后终止输出流。3.ServerSocket类
ServerSocket
类:这个类实现了服务器套接字,该对象等待通过网络的请求。
public ServerSocket(int port)
:使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号。
比如:ServerSocket server = new ServerSocket(6666);
public Socket accept()
:侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。4. TCP通信程序
【服务端】启动,创建ServerSocket对象,等待连接。
【客户端】启动,创建Socket对象,请求连接。
【服务端】接收连接,调用accept方法,并返回一个Socket对象。
【客户端】Socket对象,获取OutputStream,向服务端写出数据。
【服务端】Scoket对象,获取InputStream,读取客户端发送的数据。
到此,客户端向服务端发送数据成功。往下,服务端向客户端回写数据。
【服务端】Socket对象,获取OutputStream,向客户端回写数据。
【客户端】Scoket对象,获取InputStream,解析回写数据。
【客户端】释放资源,断开连接。
客户端/** * 客户端 * 向服务器端发送请求,接收服务器端返回请求,读取返回数据 */ public class TCPClient { public static void main(String[] args) throws IOException { //1. 创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号 Socket socket = new Socket("127.0.0.1", 6666); //2. 使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象 OutputStream os = socket.getOutputStream(); //3. 使用网络字节输出流OutputStream对象中的方法write,给服务器发送数据 //write方法只能传入int或者字节数组,传入字符串的话要进行转换 os.write("客户端向服务器发送第一次信息".getBytes()); //下面是用来接收服务器返回的数据 //4. 使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象 InputStream is = socket.getInputStream(); //5. 使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据 byte[] mes = new byte[1024]; int len = is.read(mes); System.out.println(new String(mes,0,len)); //6. 释放资源 socket.close(); } }
/** * 服务器端 * 接收客户端请求,读取客户端发送的数据,给客户端写回数据 */ public class TCPServer { public static void main(String[] args) throws IOException { //1. 创建服务器ServerSocket对象并且指定监听端口号 ServerSocket serverSocket = new ServerSocket(6666); //2. 使用ServerSocket对象中的方法accpet(),获取到请求的客户端对象Socket Socket socket = serverSocket.accept(); //3. 使用Socket对象中的方法getInputStream()获取字节输入流InputStream对象 InputStream is = socket.getInputStream(); //4. 使用字节输入流InputStream对象中的方法read,读取客户端发送的数据 byte[] mes = new byte[1024]; int len = is.read(mes); System.out.println(new String(mes,0,len)); //下面是服务器端向客户端返回数据 //5. 使用Socket对象中的方法getOutputStream获取字节输出流OutputStream对象 OutputStream os = socket.getOutputStream(); //6. 使用字节输出流OutputStream对象中的方法write,给客户端写数据 os.write("服务器端收到客户端数据".getBytes()); //7. 关闭资源 serverSocket.close(); } }
三丶UDP通信程序
1.概述
2. DatagramSocket类
3. UDP通信程序
1) 创建发送端Socket对象——DatagramSocket
2) 创建数据并将数据打包到DatagramPacket对象
3) 通过Socket发送
4) 释放相关资源
1) 创建接受端Socket对象——DatagramSocket
2) 创建包DatagramPacket对象(数据接收容器)
3) 调用接受方法接受数据
4) 解析数据包对象,取出接受到的信息
5) 释放资源
发送方public static void main(String[] args) throws IOException { String data = "UDP发送方发送数据"; //1. 实例化套接字,并指定发送方端口 DatagramSocket datagramSocket = new DatagramSocket(8888); //2. 指定数据目的地的地址,以及目标端口 InetAddress destination = InetAddress.getByName("localhost"); //3. 创建数据包,指定目标端口 DatagramPacket datagramPacket = new DatagramPacket(data.getBytes(), data.getBytes().length, destination, 9999); //4. 发送数据 datagramSocket.send(datagramPacket); //5. 释放资源 datagramSocket.close(); }
public static void main(String[] args) throws IOException { //1. 实例化套接字,并指定接收端口 DatagramSocket datagramSocket = new DatagramSocket(9999); byte[] buf = new byte[1024]; //2. 定义接收数据的数据包 DatagramPacket datagramPacket = new DatagramPacket(buf, 0, buf.length); //3. 调用接收方法 datagramSocket.receive(datagramPacket); String data = new String(datagramPacket.getData(), 0, datagramPacket.getLength()); System.out.println(data); // 4. 释放资源 datagramSocket.close(); }
四丶InetAddress和InetSocketAddress类
1.InetAddress类
位于java.net包中,封装计算机的IP地址,不包含端口号
public static void main(String[] args) throws UnknownHostException { //1. 通过getLocalHost()获得InetAddress对象 InetAddress ia1 = InetAddress.getLocalHost(); System.out.println("主机IP地址:"+ia1.getHostAddress()); System.out.println("主机名:"+ia1.getHostName()); //2. 通过getByName(域名) InetAddress ia3 = InetAddress.getByName("www.baidu.com"); System.out.println("主机IP地址:"+ia3.getHostAddress()); System.out.println("主机名:"+ia3.getHostName()); //3. 根据getByName(IP地址)获取InetAddress对象 InetAddress ia2 = InetAddress.getByName("localhost"); System.out.println("主机IP地址:"+ia2.getHostAddress()); System.out.println("主机名:"+ia2.getHostName()); }
InetSocketAddress类
位于java.net包中,此类用于实现IP套接字地址(IP地址+端口号),用于Socket通信
public static void main(String[] args) throws UnknownHostException { // 创建对象方式1 InetSocketAddress isa1 = new InetSocketAddress("localhost", 8888); // 创建对象方式2 InetAddress localHost = InetAddress.getLocalHost(); InetSocketAddress isa2 = new InetSocketAddress(localHost, 9999); System.out.println("主机名称:"+isa1.getHostName()); System.out.println("端口号:"+isa1.getPort()); }
2.URL类
1) 统一资源定位符,由四部分组成:协议,存放资源的主机域名,端口号和资源文件名
https://www.baidu.com:80/index.html
2) URL是指向互联网资源的指针,资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询
public static void main(String[] args) throws MalformedURLException { URL url = new URL("https://www.baidu.com:80/index.html"); System.out.println("协议名称:"+url.getProtocol()); System.out.println("域名:"+url.getHost()); System.out.println("端口号:"+url.getPort()); System.out.println("路径"+url.getPath()); }
五丶综合案例
1.文件上传
1) 【客户端】使用本地字节输入流
,从硬盘读取文件数据到程序中。
2) 【客户端】使用网络字节输出流(Socket提供)
,写出文件数据到服务端。
3) 【服务端】使用网络字节输入流(Socket提供)
,读取文件数据到服务端程序。
4) 【服务端】使用本地字节输出流
,写出文件数据到服务器硬盘中。
5) 【服务端】使用网络字节输出流(Socket提供)
, 向客户端返回”上传成功”信息
6) 【客户端】使用网络字节输入流(Socket提供)
, 读取服务器返回数据
7) 释放资源
/** * 文件上传客户端 */ public class UploadClient { public static void main(String[] args) throws IOException { //1. 创建本地文件输入流FileInputStream对象,绑定要上传的文件数据 FileInputStream fis = new FileInputStream(new File("d:\test.txt")); //2. 创建客户端对象,构造时绑定服务器IP地址和端口号 Socket socket = new Socket("localhost", 9999); //3. 使用Socket中的getOutputStream,获取网络字节输出流OutputStream OutputStream os = socket.getOutputStream(); //4. 使用本地文件输入流FileInputStream对象中read方法,读取文件内容 byte[] message = new byte[1024]; int len = 0; while((len=fis.read(message))!=-1){ //5. 使用网络字节输出流OutputStream对象中write方法,将读取到内容上传到服务器 os.write(message,0,len); } //6. 使用Socket中的getInputStream,获取网络字节输出流InputStream InputStream is = socket.getInputStream(); while((len=is.read(message))!=-1){ //7. 使用网络字节输入流InputStream对象中方法,获取服务器端返回的数据 System.out.println(new String(message,0,len)); } //8. 释放资源(FileInputStream,Socket) fis.close(); socket.close(); } }
/** * 文件上传服务器端 */ public class UploadServer { public static void main(String[] args) throws IOException { //1. 创建服务器端ServerSocket对象,指定监听端口号 ServerSocket serverSocket = new ServerSocket(9999); //2. 调用accept方法获得Socket对象,监听客户端信息 Socket socket = serverSocket.accept(); //3. 使用socket对象中的getInputStream,获得网络字节输入流对象 InputStream is = socket.getInputStream(); //4. 将获取到的数据保存到指定文件夹,因此要先判断文件夹是否存在 File file = new File("d:\upload"); if (!file.exists()){ file.mkdir(); } //5. 创建本地文件输出流对象FileOutputStream,构造时指定输出目的地 FileOutputStream fos = new FileOutputStream(new File("d:\upload\test.txt")); //6. 使用网络字节输入流对象方法read,读取客户端传递数据 int len=0; byte[] message = new byte[1024]; while((len=is.read(message))!=-1){ //7. 使用本次字节输出流对象FileOutputStream的write方法,保存文件 fos.write(message,0,len); } //8. 使用socket的方法得到OutputStream对象 OutputStream os = socket.getOutputStream(); //9. 使用网络字节输出流OutputStream对象向客户端返回数据 os.write(new String("上传成功").getBytes()); //10. 释放资源 fos.close(); socket.close(); } }
1) 原因:在于两个代码中都含有一个read()方法,在Java.io包中的read方法介绍是:从此输入流中读取数据,如果没有输入可用,则此方法将阻塞
.在Client中第一个read方法是读取本地文件然后通过网络字节输出流发送到服务器中,但是发送完之后,传递给服务器的文件是没有结束标记的,于是在Server中的read方法中,无法满足while循环的跳出条件因此就在此处阻塞了,Server后面的方法也就无法继续执行了,这造成了server的阻塞,与此同时,Client中第二个read方法需要读取服务端传递的网络字节输入流,但是由于Server的阻塞,导致没有向客户端反馈数据,因此Client端也阻塞了
2) 解决方案:在客户端向服务器端发送完文件之后,调用socket.shutdownOutput()方法,告知服务器已经结束了传送,将文件的读取结束标记传递给了服务器
六丶案例优化
1. 文件名称写死问题
/** * 优化1:文件名写死问题解决 * 文件命名规则:时间毫秒数+文件名后缀 * 防止同名文件被覆盖 */ String filename=System.currentTimeMillis()+".txt"; //5. 创建本地文件输出流对象FileOutputStream,构造时指定输出目的地 FileOutputStream fos = new FileOutputStream(new File(file+"\"+filename));
2. 循环接收问题
3.效率问题
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算