Java笔记16 网络编程
16.1 网络相关概念
16.1.1 网络通信
- 网络通信是通过网络将各个孤立的设备进行连接,通过信息交换实现人与人,人与计算机,计算机与计算机之间的通信
- 即将数据通过网络从一台设备传输到另一台设备的过程
- java.net包下提供了一系列的类或者接口,供程序员完成网络通信
16.1.2 网络
计算机网络(简称为网络)由若干**结点(node)和连接这些结点的链路(link)**组成
网络中的结点可以是计算机、集线器、交换机或路由器等
网络之间还可以通过路由器互连起来,这就构成了一个覆盖范围更大的计算机网络,这样的网络称为互联网(internetwork或internet)。即互联网是“网络的网络”
16.1.3 互联网的组成
互联网从其工作方式看,可以分为以下两大块:
- 边缘部分:由所有连接在互联网上的主机组成。这部分是用户直接使用的,用来进行通信(传输数据、音频或视频)和资源共享
- 核心部分:由大量网络和连接这些网络的路由器组成。这部分是为边缘部分提供服务的(提供连通性和交换)
互联网的边缘部分:处在互联网边缘的部分就是连接在互联网上的所有主机,这些主机又被称为端系统。我们常说的“主机 A 和主机 B 进行通信”实际指“主机 A 的某个进程和主机 B 的另一个进程进行通信”。在网络边缘的端系统之间的通信方式通常可以分为两类:
- 客户-服务器方式(C/S 方式):客户是服务请求方,服务器是服务提供方,这里的客户和服务器都指的是计算机进程(软件)
- 对等方式(P2P 方式):指两台主机在通信时不区分哪一个是服务请求方哪一个是服务提供方。只要两台主机都运行了对等连接软件(P2P 软件),他们就可以进行平等的、对等连接通信
网络的核心部分:在网络核心部分起特殊作用的是路由器(router),它是一种专用计算机(但不叫主机)。路由器是实现**分组交换(packet switching)**的关键构件,其任务是转发收到的分组。这是网络核心部分最重要的功能
16.1.4 互联网的分类
按照网络的作用范围进行分类(由大到小):
- 广域网 WAN(Wide Area NetWork):广域网的作用范围通常为几十到几千公里,因而有时也称为远程网。广域网是互联网的核心部分,其任务是通过长距离运送主机所发送的数据。
- 城域网 MAN(Metropolitan Area Network):城域网的作用范围一般是一个城市,可跨越几个街区甚至整个城市,其作用距离约为 5 ~ 50 km。城域网可以为一个或几个单位所拥有,但也可以是一种公用设施,用来将多个局域网进行互联。目前很多城域网采用的是以太网技术
- 局域网 LAN(Local Area Network):局域网一般用微型计算机或工作站通过高速通信线路相连(速率通常在 10 Mbit/s 以上),但地理上则局限在较小的范围(如 1 km 左右)
- 个人区域网 PAN(Personal Area Network):个人区域网就是在个人工作的地方把属于个人使用的电子设备用无线技术连接起来的网络,因此也常称为无线个人区域网WPAN(Wireless PAN),其作用范围很小,大约在 10 m 左右
按照网络的使用者进行分类
- 公用网(public network):这里是指电信公司(国有或私有)出资建造的大型网络。“公用”的意思是所有愿意按照电信公司的规定交纳费用的人都可以使用这种网络
- 专用网(private network):这是某个部门为满足本单位的特殊业务工作的需要而建造的网络。这种网络不向本单位以外的个人提供服务。例如,军队、铁路、银行、电力等系统均有本系统的专用网
16.1.5 计算机网络的性能指标
速率:网络技术中的速率指的是数据的传输速率,它也称为数据率(data rate)或比特率(bit rate)。速率是计算机网络中最重要的一个性能指标,它的单位是 bit/s(比特每秒)(或 b/s ,有时也写作 bps),当数据率较高时,就常常在 bit/s 前加上一个字母。如,k = 10³ = 千,M = 10⁶ = 兆,G = 10⁹ = 吉,T = 10¹² = 太,P = 10¹⁵ = 拍,E = 10¹⁸ = 艾,Z = 10²¹ = 泽,Y = 10²⁴ = 尧。这样 4 x 10¹⁰ bit/s 的数据率就记为 40 Gbit/s
带宽:在计算机网络中,带宽用来表示网络中某通道传送数据的能力,因此网络带宽表示在单位时间内网络中的某信道所能通过的“最高数据率”,所以带宽的单位就是数据率的单位 bit/s,即“比特每秒”
吞吐量:表示在单位时间内通过某个网络(或信道、接口)的实际的数据量。可以理解为带宽为某带宽为 1 Gbit/s 的通道的额定速率为 1 Gbit/s,即 每秒最多通过 1 Gbit 的数据,而吞吐量为某一秒内实际通过的数据量,也就是说,1 Gbit/s 的通道吞吐量可能只有 100 Mbit/s
时延:指数据(一个报文或分组,甚至比特)从网络(或链路)的一端传送到另一端所需的时间,有时也称为延迟或迟延。网络中的时延由以下几部分组成:
发送时延:主机或路由器发送数据帧所需要的时间,也就是从发送数据帧的第一个比特算起,到帧的最后一个比特发送完毕所需的时间,因此也叫做传输时延。计算公式为:
发送时延=数据帧长度(bit)发送速率(bit/s)发送时延=\frac{数据帧长度(bit)}{发送速率(bit/s)} 发送时延=发送速率(bit/s)数据帧长度(bit)传播时延:电磁波在信道中传播一定的距离需要花费的时间。计算公式为:
传播时延=信道长度(m)电磁波在信道上的传播速率(m/s)传播时延=\frac{信道长度(m)}{电磁波在信道上的传播速率(m/s)} 传播时延=电磁波在信道上的传播速率(m/s)信道长度(m)[^]: 电磁波在铜线电缆中的传播速度约为 3.0 x 10⁵ km/s,在光纤中的传播速率约为 2.0 x 10⁵ km/s
处理时延:主机或路由器在收到分组时需要花费一定的时间进行处理,例如分析分组的首部、从分组中提取数据部分、进行差错校验或查找适当的路由等,这就产生了处理时延
排队时延:分组在经过网络传输时,要经过许多路由器。分组在进入路由器后要先在输入队列中排队等待处理,在路由器确定了转发接口后,还要在输出队列中排队等待转发,这就产生了排队时延
总时延:数据在网络中经历的总时延就是以上四种时延之和:
总时延=发送时延+传播时延+处理时延+排队时延总时延=发送时延+传播时延+处理时延+排队时延 总时延=发送时延+传播时延+处理时延+排队时延
时延带宽积:将 传播时延 和 带宽 相乘就得到了传播时延带宽积,即:
时延带宽积=传播时延×带宽时延带宽积=传播时延 \times 带宽 时延带宽积=传播时延×带宽
例如,设某段链路的传播时延为 20 ms,带宽为 10 Mbit/s,可以算出:
时延带宽积=20×10−3×10×106=2×105bit时延带宽积=20\times10^{-3}\times10\times10^6=2\times10^5bit 时延带宽积=20×10−3×10×106=2×105bit
这就表明,若发送段连续发送数据,则在发送的第一个比特即将到达终点时,发送段就已经发送了 20 万个比特,而这 20 万个比特都正在链路上向前方移动。因此,链路的时延带宽积又称为以比特为单位的链路长度往返时间 RTT:在计算机网络中,往返时间也是一个重要的性能指标。这是因为在许多情况下,互联网上的信息不仅仅单方向传输而是双向交互的,因此我们有时很需要知道双向交互一次所需的时间。例如,A 向 B 发送数据,。如果数据长度为 100 MB,发送速率为 100 Mbit/s,那么:
发送时间=数据长度发送速率=100×220×8100×106≈8.39s发送时间=\frac{数据长度}{发送速率}=\frac{100\times2^{20}\times8}{100\times10^6}\approx8.39s 发送时间=发送速率数据长度=100×106100×220×8≈8.39s
如果 B 正确收完 100 MB 的数据后,就立即向 A 发送确认。假定 A 只有收到 B 的确认信息后,才能继续向 B 发送数据。显然,这里需要等待一个往返时间RTT(这里假定确认消息很短,可忽略 B 发送确认的时间)。如果 RTT = 2 s,那么可以算出 A 向 B 发送数据的有效数据率:
有效数据率=数据长度发送时间+RTT=100×220×88.39+2≈80.7Mbit/s有效数据率=\frac{数据长度}{发送时间+RTT}=\frac{100\times2^{20}\times8}{8.39+2}\approx80.7Mbit/s 有效数据率=发送时间+RTT数据长度=8.39+2100×220×8≈80.7Mbit/s利用率:利用率有 信道利用率 和 网络利用率 两种
- 信道利用率指出某信道有百分之几的时间是被利用的(有数据通过),完全空闲的信道的利用率为零
- 网络利用率则是全网络的信道利用率的加权平均值
- 信道利用率并非越高越好,信道或网络的利用率过高会产生非常大的时延
16.1.6 IP地址
- 概念:用于唯一标识网络中的每台主机
- Windows查看ip地址命令:
ipconfig
,Linux查看ip地址命令:ifconfig
- ip地址的表示形式:点分十进制
xx.xx.xx.xx
- 每一个十进制数的范围是:0 ~ 255
- ip地址的组成 = 网络地址 + 主机地址。比如:192.168.16.69
- IPV6是互联网工程任务组设计的用于替换IPV4的下一代IP地址,其地址数量号称可以为全世界的每一粒沙子编上一个地址
- 由于IPV4的最大问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPV6的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备接入互联网的障碍
- IPV4地址的分类:
16.1.7 域名和端口号
- 域名
- 如 www.baidu.com
- 好处:方便记忆,解决记ip地址的困难
- 概念:将ip地址映射成域名(通过HTTP协议)
- 端口号
- 概念:用于标识计算机上某个特定的网络程序
- 表示形式:以整数形式,端口范围是 0 ~ 65535【0 ~ 2^16 -1】
- 0 ~ 1024已经被占用,如 ssh 22、ftp 21、smtp 25、http 80等
- 常见的网络程序默认端口号:
- tomcat:8080
- mysql:3306
- oracle:1521
- sqlserver:1433
16.1.8 网络通信协议
TCP/IP(Transmission Control Protocol/Internet Protocol)中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互联网的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的
OSI模型 | TCP/IP模型 | TCP/IP模型各层对应协议 |
应用层 | 应用层 | HTTP、FTP、telnet、DNS... |
表示层 | ||
会话层 | ||
传输层 | 传输层(TCP) | TCP、UDP... |
网络层 | 网络层(IP) | IP、ICMP、ARP... |
数据链路层 | 物理+数据链路层 | Link |
物理层 |
- TCP协议:传输控制协议
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
- 传输前,采用“三次握手”方式,是可靠的
- TCP协议进行通信的两个应用程序:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
- UDP协议:用户数据协议
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据包的大小限制在64K内,不适合传输大量数据
- 因无需连接,故是不可靠的
- 发送数据结束时无需释放资源(因为不是面向连接的),速度快
16.2 InetAddress类
16.2.1 相关方法
getLocalHost
:获取本机 InetAddress 对象getByName
:根据指定主机名/域名获取 ip 地址对象getHostName
:获取 InetAddress 对象的主机名getHostAddress
:获取 InetAddress 对象的地址
16.2.2 示例
public class InetAddressDemo {public static void main(String[] args) throws UnknownHostException {//获取本机的 InetAddress 对象InetAddress localHost = InetAddress.getLocalHost();System.out.println(localHost); //LAPTOP-57CI10E5/192.168.1.103//根据指定主机名获取 InetAddress 对象InetAddress host1 = InetAddress.getByName("LAPTOP-57CI10E5");System.out.println("host1 name="+host1.getHostName());//host1=LAPTOP-57CI10E5//根据域名返回 InetAddress 对象InetAddress host2 = InetAddress.getByName("www.baidu.com");System.out.println("host2 address="+host2.getHostAddress());//host2=39.156.66.18}
}
16.3 Socket
14.3.1 介绍
- 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准
- 网络的两端都要有 Socket,是两台主机间通信的端点
- 网络通信其实就是 Socket 间的通信
- Socket 允许程序把网络连接当成一个流,数据在两个 Socket 间通过 I/O 传输
- 一般主动发起通信的应用程序为客户端,等待通信请求的是服务端
- 两端的 Socket 都有
getOutputStream()
方法和getInputStream()
方法进行读写数据 - 基于 Socket 可以进行 TCP 编程 和 UDP 编程
【主机/客户端 发起连接[Socket]】 <—数据通道—> 【[Socket]主机/服务端 接收请求连接(监听)】
16.4 TCP 网络通信编程
16.4.1 介绍
- 基于客户端—服务端的网络通信
- 底层使用的是 TCP/IP 协议
- 应用场景举例:客户端发送数据,服务端接收并显示在控制台
- 基于 Socket 的 TCP 编程
16.4.2 示例1 使用字节流
- 编写一个服务器端和一个客户端
- 服务器端在 9999 端口监听
- 客户端连接到服务器端,发送“hello,server”,然后退出
- 服务端连接到客户端发送的消息,输出并退出
//服务端
public class SocketTCP01Server {public static void main(String[] args) throws IOException {//在本机的 9999 端口监听,等待连接//要求在服务端主机 9999 端口没有被占用//ServerSocket 可以通过 accept() 返回多个 Socket【多个客户端连接服务器的并发】ServerSocket serverSocket = new ServerSocket(9999);System.out.println("服务端在 9999 端口监听,等待连接");//当没有客户端连接 9999 端口时,程序会阻塞,等待连接//如果有客户端连接,则会返回一个 Socket 对象,程序继续执行Socket socket = serverSocket.accept();System.out.println("服务器端 socket = "+socket.getClass());//通过 socket.getInputStream() 读取客户端写入到数据通道的数据InputStream inputStream = socket.getInputStream();byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) != -1) {System.out.println(new String(buf,0,readLen));}//关闭流和 SocketinputStream.close();socket.close();serverSocket.close();System.out.println("服务端退出了...");}
}
//客户端
public class SocketTCP01Client {public static void main(String[] args) throws IOException {//连接服务端(ip,端口)//连接 InetAddress.getLocalHost() 也就是本机的 9999 端口//连接上后,生成 Socket 对象Socket socket = new Socket(InetAddress.getLocalHost(), 9999);System.out.println("客户端socket = "+socket.getClass());//通过 socket.getOutputStream() 获得和 Socket 对象关联的输出流OutputStream outputStream = socket.getOutputStream();//通过输出流写入数据到数据通道outputStream.write("hello,server".getBytes());//关闭流对象和 SocketoutputStream.close();socket.close();System.out.println("客户端退出了...");}
}
16.4.3 示例2 使用字节流
- 编写一个服务端和客户端
- 服务端在 9999 端口监听
- 客户端连接到服务端后,发送“hello,server”,并接收到服务端回发的“hello,client”,再退出
- 服务端接收到客户端发送的信息,输出,并发送“hello,client”再退出
//服务端
public class SocketTCP02Server {public static void main(String[] args) throws IOException {//在本机的 9999 端口监听,等待连接//要求在服务端主机 9999 端口没有被占用//ServerSocket 可以通过 accept() 返回多个 Socket【多个客户端连接服务器的并发】ServerSocket serverSocket = new ServerSocket(9999);System.out.println("服务端在 9999 端口监听,等待连接");//当没有客户端连接 9999 端口时,程序会阻塞,等待连接//如果有客户端连接,则会返回一个 Socket 对象,程序继续执行Socket socket = serverSocket.accept();System.out.println("服务器端 socket = "+socket.getClass());//通过 socket.getInputStream() 读取客户端写入到数据通道的数据InputStream inputStream = socket.getInputStream();byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) != -1) {System.out.println(new String(buf,0,readLen));}//通过 socket.getOutputStream() 获取输出流,写入数据到数据通道OutputStream outputStream = socket.getOutputStream();outputStream.write("hello,client".getBytes());//设置一个输出结束标记socket.shutdownOutput();//关闭流和 SocketinputStream.close();outputStream.close();socket.close();serverSocket.close();System.out.println("服务端退出了...");}
}
//客户端
public class SocketTCP02Client {public static void main(String[] args) throws IOException {//连接服务端(ip,端口)//连接 InetAddress.getLocalHost() 也就是本机的 9999 端口//连接上后,生成 Socket 对象Socket socket = new Socket(InetAddress.getLocalHost(), 9999);System.out.println("客户端socket = "+socket.getClass());//通过 socket.getOutputStream() 获得和 Socket 对象关联的输出流OutputStream outputStream = socket.getOutputStream();//通过输出流写入数据到数据通道outputStream.write("hello,server".getBytes());//设置一个输出结束标记socket.shutdownOutput();//通过 socket.getInputStream() 获取输入流,读取数据通道的数据并显示InputStream inputStream = socket.getInputStream();byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) != -1) {System.out.println(new String(buf,0,readLen));}//关闭流对象和 SocketinputStream.close();outputStream.close();socket.close();System.out.println("客户端退出了...");}
}
16.4.4 示例3 使用字符流
- 编写一个服务端和客户端
- 服务端在 9999 端口监听
- 客户端连接到服务端后,发送“hello,server”,并接收到服务端回发的“hello,client”,再退出
- 服务端接收到客户端发送的信息,输出,并发送“hello,client”再退出
//服务端
public class SocketTCP03Server {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(9999);System.out.println("服务端在 9999 端口监听,等待连接");Socket socket = serverSocket.accept();//接收数据InputStream inputStream = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));String line = br.readLine();System.out.println(line);//发送数据OutputStream outputStream = socket.getOutputStream();BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));bw.write("hello,client 字符流");bw.newLine();//插入换行符,表示写入内容结束bw.flush();//字符流需要手动刷新,否则不会写入数据通道socket.shutdownOutput();//对方使用循环读取需要设置结束标记,若调用一次readLine(),不需要此标记//关闭bw.close();br.close();socket.close();serverSocket.close();}
}
//客户端
public class SocketTCP03Client {public static void main(String[] args) throws IOException {Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//发送数据OutputStream outputStream = socket.getOutputStream();BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));bw.write("hello,server 字符流");bw.newLine();//插入换行符,表示写入内容结束,要求对方用readLine()读bw.flush();//字符流需要手动刷新,否则不会写入数据通道//接收数据InputStream inputStream = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));String line = null;while ((line = br.readLine()) != null) {System.out.println(line);}//关闭br.close();bw.close();socket.close();}
}
16.4.5 示例4 上传文件
- 编写一个服务端和一个客户端
- 服务端在 8888 端口监听
- 客户端连接到服务端,发送一张图片
- 服务端接收到客户端发送的图片后,保存在 src 下,发送“收到图片”再退出
- 客户端接收到服务端发送的“收到图片”,再退出
- 该程序要求使用 StreamUtils.java 工具类
/*** 工具类*/
public class StreamUtils {/*** 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]** @param is* @return* @throws IOException*/public static byte[] streamToByteArray(InputStream is) throws IOException {ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象byte[] b = new byte[1024];//字节数组int len;while ((len = is.read(b)) != -1) {//循环读取bos.write(b, 0, len);//把读取到的数据,写入bos }byte[] array = bos.toByteArray();//然后将bos 转成字节数组bos.close();return array;}/*** 功能:将InputStream转换成String** @param is* @return* @throws IOException*/public static String streamToString(InputStream is) throws IOException {BufferedReader reader = new BufferedReader(new InputStreamReader(is));StringBuilder builder = new StringBuilder();String line;while ((line = reader.readLine()) != null) {builder.append(line + "\r\n");}return builder.toString();}}
//服务端
public class TCPFileUploadServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8888);System.out.println("监听 8888 端口,等待客户端连接...");Socket socket = serverSocket.accept();//读取客户端发送的存放图片数据的字节数组InputStream inputStream = socket.getInputStream();BufferedInputStream bis = new BufferedInputStream(inputStream);byte[] picData = StreamUtils.streamToByteArray(bis);//将得到的字节数组写入指定路径,就得到一个文件String destFilePath = "src\\bg.png";BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));bos.write(picData);bos.close();//回发消息OutputStream outputStream = socket.getOutputStream();BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));bw.write("服务端收到图片");bw.flush();socket.shutdownOutput();//设置写入结束标记//使用结束标记而非换行符标记写入结束,客户端可以使用字节流接收//释放资源bw.close();bis.close();socket.close();serverSocket.close();}
}
//客户端
public class TCPFileUploadClient {public static void main(String[] args) throws IOException {//客户端连接服务端,得到 Socket 对象Socket socket = new Socket(InetAddress.getLocalHost(), 8888);//读取图片转换为字节数组String filePath = "C:\\Users\\ZHF\\Desktop\\bg.png";BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));byte[] picData = StreamUtils.streamToByteArray(bis);bis.close();//获取 socket 对应的输出流,通过输出流发送数据OutputStream outputStream = socket.getOutputStream();BufferedOutputStream bos = new BufferedOutputStream(outputStream);bos.write(picData);socket.shutdownOutput();//接收服务端回复的消息InputStream inputStream = socket.getInputStream();String mes = StreamUtils.streamToString(inputStream);System.out.println(mes);//释放资源bos.close();socket.close();}
}
16.4.6 示例5 下载文件
- 编写客户端和服务端程序
- 客户端输入一个音乐文件名,比如 高山流水
- 服务端收到音乐名后,判断有没有这个文件,有就返回这个文件,没有则返回一个默认文件
- 客户端收到文件后,保存到本地
- 可以使用工具类 StreamUtils.java
工具类文件 StreamUtils.java 同上
//服务端
public class TCPFileDownloadServer {public static void main(String[] args) throws IOException {//监听 8888 端口ServerSocket serverSocket = new ServerSocket(8888);System.out.println("正在等待客户端请求...");Socket socket = serverSocket.accept();//获取音乐名BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String musicName = br.readLine();System.out.println("要下载的音乐为:" + musicName);//判断是否有该音乐File file = new File("Resource\\" + musicName + ".mp3");if (!file.exists())file = new File("Resource\\无名.mp3");//读取音乐文件BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));byte[] musicData = StreamUtils.streamToByteArray(bis);//回发给客户端BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());bos.write(musicData);socket.shutdownOutput();//释放资源bos.close();bis.close();br.close();socket.close();serverSocket.close();}
}
//客户端
public class TCPFileDownloadClient {public static void main(String[] args) throws IOException {//用户输入Scanner scanner = new Scanner(System.in);System.out.print("请输入音乐名:");String musicName = scanner.next();//将音乐名发送到客户端Socket socket = new Socket(InetAddress.getByName("192.168.1.104"), 8888);BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(musicName);bw.newLine();bw.flush();//接收音乐文件InputStream inputStream = socket.getInputStream();byte[] musicData = StreamUtils.streamToByteArray(inputStream);//写入到本地String filePath = "C:\\Users\\ZHF\\Desktop\\" + musicName + ".mp3";BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));bos.write(musicData);System.out.println("下载完成");//释放资源bos.close();inputStream.close();bw.close();socket.close();scanner.close();}
}
16.4.7 netstat 命令
netstat -an
可以查看当前主机网络情况,包括端口监听情况和网络连接状况netstat -an | more
可以分页显示- Listening 表示某个端口正在监听
- ESTABLISHED表示连接上了
16.5 UDP 网络通信编程
16.5.1 介绍
- 类DatagramSocket 和DatagramPacket[数据包/数据报]实现了基于UDP 协议网络程序。
- UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP 数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
- DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和 端口号以及接收端的IP地址和端口号。
- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方 的连接
16.5.2 基本流程
- 核心的两个类/对象DatagramSocket与DatagramPacket
- 建立发送端,接收端(没有服务端和客户端概念)
- 发送数据前,建立数据包/报DatagramPacket对象
- 调用DatagramSocket的发送、接收方法
- 关闭DatagramSocket
16.5.3 示例
- 编写一个接收端A,和一个发送端B
- 接收端A在9999端口等待接收数据(receive)
- 发送端B向接收端A发送数据"hello,明天吃火锅~"
- 接收端A接收到发送端B发送的数据,回复“好的,明天见",再退出
- 发送端接收回复的数据,再退出
public class UDPReceiverA {public static void main(String[] args) throws IOException {//创建 DatagramSocket 对象,监听 9999 端口DatagramSocket datagramSocket = new DatagramSocket(9999);//构建一个 DatagramPacket 对象,准备接收数据//UDP数据包最大 64K,这里仅接收一句话 1K足够byte[] buf = new byte[1024];DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);//调用接受方法,将接收到的 DatagramPacket 对象填充到 datagramPacketSystem.out.println("接收端A正在等待接收数据...");datagramSocket.receive(datagramPacket);//将数据包拆包,取出数据并显示int packetLength = datagramPacket.getLength();byte[] packetData = datagramPacket.getData();String s = new String(packetData, 0, packetLength);System.out.println(s);//构建回发消息数据包byte[] bytes = "好的,明天见".getBytes(StandardCharsets.UTF_8);DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.1.104"), 9998);//回发消息datagramSocket.send(packet);//释放资源datagramSocket.close();}
}
public class UDPSenderB {public static void main(String[] args) throws IOException {//创建 DatagramSocket 对象,监听 9998 端口DatagramSocket datagramSocket = new DatagramSocket(9998);//构建数据包byte[] sendData = "hello,明天吃火锅~".getBytes(StandardCharsets.UTF_8);DatagramPacket datagramPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("192.168.1.104"), 9999);//发送数据包datagramSocket.send(datagramPacket);//接受回发消息byte[] buf = new byte[1024];DatagramPacket receivePacket = new DatagramPacket(buf, buf.length);datagramSocket.receive(receivePacket);//取出数据String s = new String(receivePacket.getData(), 0, receivePacket.getLength());System.out.println(s);//释放资源datagramSocket.close();}
}
16.6 练习
16.6.1 TCP练习
- 使用字符流的方式,编写一个客户端程序和服务器端程序,
- 客户端发送"name",服务器端接收到后,返回“我是nova", nova是你自己的名字.
- 客户端发送"hobby",服务器端接收到后,返回“编写java程序"
- 不是这两个问题,回复“你说啥呢”
- 问题:目前,我们只能问一次,就退出了,怎么可以问多次?->while->聊天
public class TCPServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8888);Socket socket = serverSocket.accept();//接收BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String readLine = br.readLine();System.out.println(readLine);//回发String rep = null;if ("name".equals(readLine))rep = "我是 nova";else if ("hobby".equals(readLine))rep = "编写Java程序";elserep = "你说啥呢";BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(rep);bw.newLine();bw.flush();//释放资源bw.close();br.close();socket.close();serverSocket.close();}
public class TCPClient {public static void main(String[] args) throws IOException {//输入Scanner scanner = new Scanner(System.in);System.out.println("请输入:");String next = scanner.next();//发送Socket socket = new Socket(InetAddress.getByName("192.168.1.104"), 8888);BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(next);bw.newLine();bw.flush();//接收回发BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String readLine = br.readLine();System.out.println(readLine);//释放资源br.close();bw.close();socket.close();}
}
16.6.2 UDP练习
- 编写一个接收端A,和一个发送端B,使用UDP协议完成
- 接收端在8888端口等待接收数据(receive)
- 发送端向接收端发送数据“四大名著是哪些”
- 接收端接收到发送端发送的问题后,返回"四大名著是《红楼梦》…",否则返回 what?
- 接收端和发送端程序退出
public class UDPA {public static void main(String[] args) throws IOException {//监听8888端口DatagramSocket datagramSocket = new DatagramSocket(8888);//接收数据包byte[] buf = new byte[1024];DatagramPacket receivePacket = new DatagramPacket(buf, buf.length);datagramSocket.receive(receivePacket);//取出数据String receiveStr = new String(receivePacket.getData(), 0, receivePacket.getLength());System.out.println(receiveStr);//回发消息String rep = null;if ("四大名著是哪些".equals(receiveStr))rep = "四大名著是《红楼梦》、《西游记》、《水浒传》和《三国演义》";elserep = "what?";byte[] repBytes = rep.getBytes(StandardCharsets.UTF_8);DatagramPacket repPacket = new DatagramPacket(repBytes, repBytes.length, InetAddress.getByName("192.168.1.104"), 9999);datagramSocket.send(repPacket);//释放资源datagramSocket.close();}
}
public class UDPB {public static void main(String[] args) throws IOException {//获取输入Scanner scanner = new Scanner(System.in);System.out.println("请输入:");String next = scanner.next();//监听 9999 端口DatagramSocket datagramSocket = new DatagramSocket(9999);//发送数据byte[] bytes = next.getBytes(StandardCharsets.UTF_8);DatagramPacket sendPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.1.104"), 8888);datagramSocket.send(sendPacket);System.out.println("发送完毕");//接收回发数据byte[] buf = new byte[1024];DatagramPacket receivePacket = new DatagramPacket(buf, buf.length);datagramSocket.receive(receivePacket);String receiveStr = new String(receivePacket.getData(), 0, receivePacket.getLength());System.out.println(receiveStr);//释放资源datagramSocket.close();}
}
Java笔记16 网络编程相关推荐
- 【java笔记】网络编程概述
[java笔记]TCP通信程序_m0_52043808的博客-CSDN博客 [java笔记]网络编程:文件上传案例_m0_52043808的博客-CSDN博客 网络编程: 在一定协议下,实现两台计算机 ...
- 大数据 -- java基础16 网络编程 TCP UDP
1.网络编程的三要素:(1)IP地址(2)端口号(3)协议 2.IP地址 : 网络中计算机唯一标识. (1)IP地址在计算机中存储的时候是由二进制的形式进行存储的:IP:192.168.7.42 十进 ...
- 【java笔记】网络编程:文件上传案例
原理:文件的复制 客户端读取本地的文件,把文件上传到服务器,服务器把上传的文件保存到服务器的硬盘上 步骤: 1.客户端使用本地的字节输入流,读取要上传的文件 2.客户端使用网路字节输出流,把读取的文件 ...
- Java基础学习笔记之网络编程
Java基础之网络编程 1.网络编程概述 什么是网络编程 指的是在多个设备(计算机)执行,其中的设备使用一个网络中的所有连接到对方编写程序 网络编程的目的 与其他计算机进行通信 网络编程的问题 1.如 ...
- Java进阶之网络编程
网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...
- java程序设计之网络编程基础教程_Java程序设计之网络编程基础教程
基本信息 书名:Java程序设计之网络编程基础教程(21世纪高等学校计算机基础实用规划教材) :43.50元 作者:李芝兴 主编 出版社:清华大学出版社 出版日期:2012-12-1 ISBN:978 ...
- Java学习之网络编程实例
转自:http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 多谢分享 网络编程 网络编程对于很多的初学者来说,都是很向往的一 ...
- 黑马程序员_java自学学习笔记(八)----网络编程
黑马程序员_java自学学习笔记(八)----网络编程 android培训. java培训.期待与您交流! 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无 ...
- 学习Java第十九天(一):1、Java中的网络编程
1.Java中的网络编程 什么是网络? 在计算机领域中网络是信息传输,接收共享的虚拟平台,通过它把各个点,面,体的联系到一起,从而实现这些资源的共享. 作用:信息传输,资源共享 有点:资源共享免费 O ...
- Java之HTTP网络编程(下篇:网页浏览器程序设计)
目录 一.本篇简介 二.URL类 三.基于URL类的网页下载 1.发送按钮 2.接收数据的多线程 四.URL网页下载客户端 五.编写web浏览器 1.WebEngine类 2.WebView类 3.W ...
最新文章
- 【中国剩余定理】POJ 1006 HDU 1370 Biorhythms
- matlab 子图title的位置_Plotly_多个子图
- HTML之页面结构分析
- 警告!你的隐私正在被上亿网友围观偷看!
- 在markdown中通过html语法实现表格中的有序列表和无需列表
- html5新增标签/删除标签
- ADSL桥接模式和路由模式的区别(转)
- 自动化运维工具(光纤交换机接口功率监控)
- Maven中的dependencyManagement 详解
- pc模仿移动端滚动条样式,好看就对了
- 读研究生应该做什么?导师会帮你什么?
- oracle vm 产品介绍,Oracle VM Server for SPARC 产品概述
- 基于产生式表示的动物识别系统
- matlab 常值函数,matlab常用数值函数大全
- Echarts水滴图
- narx神经网络 matlab,神经网络 NARX
- C++多线程:thread_local
- Android修行手册 - 实现可折叠TextView,仅一个类复制即用
- python:读取Excel文件
- Windows注入与拦截(3) -- 使用钩子方式完成DLL注入
热门文章
- spacy实体关系抽取_使用spacy从Wikipedia文章中命名实体识别
- 洛谷刷题笔记 最高分数的学生姓名
- js 根据公历日期 算出农历_Javascript农历与公历相互转换
- 量子信息与量子计算_为什么2020年代属于量子计算
- 国际植物基博览会2022年6月首次亮相上海;海瑞温斯顿珠宝王国在北京开设新零售沙龙 | 知消...
- 区块链在保险业的应用
- unity3d 本地化数据PlayerPrefs详解
- Delphi下实现全屏快速找图找色 四、BitmapData.pas的使用
- 终于把Edison板子上线了
- 武汉大学计算机系就业方向如何,武汉大学有什么王牌专业?它们的就业在哪些方向?...