大数据学习笔记——Java篇之网络编程基础
Java网络编程学习笔记
1. 网络编程基础知识
1.1 网络分层图
网络分层分为两种模型:OSI模型以及TCP/IP网络模型,前者模型分为7层,是一个理论的,参考的模型;后者为实际应用的模型,具体对应关系见下图:

1.2 网络编程三要素之IP地址
目前的版本是ipv4,采用的是点分十进制的表示方式(dotted-decimal notation),一共4位,每一位表示一个字节,因为IP地址是没有负数的,因此表数范围是0-255,子网掩码的存在使得一个IP地址被区分为了两个部分,网络地址以及主机地址,原理如下:比如一个子网掩码为255.255.255.0,实际上相当于将整个地址的前三位划分成了网络地址,而最后一位划分成了主机地址,网络地址越少,主机位越多,可分配的主机数量就越多,IP地址的分类图如下:

一般企业使用的是C类网址,校园网使用的是B类网址,而A类网址往往是政府,国家使用
1.3 IP地址编程实战——InetAddress类
查看该类的API可知,它的构造方法是私有的,因此无法通过new的方式创建对象,而是通过getByName这一静态方法获取到实例对象的:
/*
演示InetAddress类的基本API
*/
public class InetAddressDemo {
public static void main(String[] args) throws Exception {
//1.通过给定IP地址的方式获取到InetAddress对象
InetAddress ip1 = InetAddress.getByName("192.168.153.1");
System.out.println(ip1);
//2.通过给定主机名的方式获取到InetAddress对象
InetAddress ip2 = InetAddress.getByName("DESKTOP-LEPR355");
System.out.println(ip2);
//3.通过获取到的InetAddress解析出主机名
System.out.println(ip1.getHostName());
//4.通过获取到的InetAddress解析出主机的IP地址
System.out.println(ip2.getHostAddress()); }
}
结果显示:解析成功!
// 控制台中的解析结果如下:
/192.168.153.1
DESKTOP-LEPR355/192.168.153.1
DESKTOP-LEPR355
192.168.153.1
1.4 网络编程三要素之端口(port)
端口号是用来唯一表示计算机上运行着的进程的,以一个数字进行指定,该数字的范围是0-65535共65536个,其中系统进程使用的是0-1023,因此应用程序只能使用后面的数字,否则会发生冲突,使得应用程序运行失败
1.5 网络编程三要素之协议(Protocal)
两个主机之间想要相互通信,必须要使用相同的语言,对于数据的格式,错误控制,重传机制等的一系列规范就是协议
1.5.1 UDP编程
UDP是User Datagram Protocal的缩写:用户数据报协议,它的特点是不用建立连接,发送端只管发送数据给接收端而不必考虑接收端是否真的接收到了数据,数据是被封装成数据包的,限制在64K,数据包自己知道它应该去哪一个主机的哪一个端口,因为UDP编程的这一特性,使得它的发送效率高,速度快,通常可以用在发送短信或是网络电话,网络会议等场景上,发送端和接收端的编程步骤如下所示:
其中receive方法是一个阻塞式方法,没有信息发送过来,此方法就会一直处于等待状态


使用同一台主机上的两个端口模拟UDP编程编写一个简易聊天程序
信息发送端代码:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner; /*
使用UDP编程模拟一个简易聊天程序,发送端输入"bye"退出程序
使用同一台主机的两个不同的端口模拟两台不同的主机
*/
public class DatagramSocketSender {
public static void main(String[] args) throws Exception {
//新建一个DatagramSocket对象
DatagramSocket ds = new DatagramSocket();
//新建一个扫描器
Scanner sc = new Scanner(System.in);
while(true){
//接收用户键入信息
System.out.println("Please input your message: ");
String line = sc.nextLine();
//判断用户输入的是不是"bye"
if(line.equals("bye")){
break;
}else{
//获取输入信息字符串的字节数组对象
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("localhost"), 8888);
ds.send(dp);
}
}
ds.close();
}
}
信息接收端代码:
import java.net.DatagramPacket;
import java.net.DatagramSocket; /*
模拟简易聊天程序的接收端,一般情况下,接收端看成是服务器,是不会轻易关闭的
*/
public class DatagramSocketReceiver {
public static void main(String[] args) throws Exception {
//绑定端口
DatagramSocket ds = new DatagramSocket(8888);
byte[] bys = new byte[64 * 1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
//服务端一般来说不会关闭
while(true){
//接收来自发送端的数据
ds.receive(dp);
//进行解析
byte[] data = dp.getData();
int len = dp.getLength();
System.out.println(new String(data,0,len));
}
}
}
使用UDP编程发送文件
文件发送端代码:
import java.io.BufferedReader;
import java.io.FileReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress; /*
使用UDP编程模拟文件的发送端
需要注意的是,因为要让文件接收端知道什么时候文件发送完成,需要写一个结束标记符
*/
public class FileSender {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("e:/test/a.txt"));
DatagramSocket ds = new DatagramSocket();
String line = null;
while((line = br.readLine()) != null){
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("localhost"), 8888);
ds.send(dp);
}
//文件已经全部发送完,最后发送一个结束标记,"886"
byte[] bys = "886".getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("localhost"), 8888);
ds.send(dp);
//关闭资源
br.close();
ds.close();
}
}
文件接收端代码:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket; /*
使用UDP编程模拟文件接收方,当接收到字符"886"时表示文件已经发送完成,退出
*/
public class FileReceiver {
public static void main(String[] args) throws Exception {
BufferedWriter bw = new BufferedWriter(new FileWriter("e:/test/aa.txt"));
//指定端口
DatagramSocket ds = new DatagramSocket(8888);
//封装数据包
byte[] bys = new byte[64 * 1024];
DatagramPacket dp = new DatagramPacket(bys,bys.length);
//解析接收到的数据并将其写出到另一个文件中去
while(true){
//接收数据
ds.receive(dp);
byte[] data = dp.getData();
int len = dp.getLength();
String line = new String(data,0,len);
if(line.equals("886")){
break;
}else{
bw.write(line);
bw.newLine();
bw.flush();
}
}
//关闭资源
bw.close();
ds.close();
}
}
上述代码是对文本文件进行操作,因为是按行进行读取,因此可以将文件的每一行数据封装成一个数据包,但是,如果操作的是图片,视频,mp3等非文本文件,就需要对代码进行更改了
图片发送端代码
import java.io.File;
import java.io.RandomAccessFile;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress; /*
UDP编程模拟发送一张图片
*/
public class PictureSender {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
//使用RandomAccessFile,因为可以移动指针
RandomAccessFile raf = new RandomAccessFile("e:/test/picture.png", "rw");
//新建一个字节数组进行数据拷贝,大小应小于64k,因为要存放一些控制字符
int size = 60 * 1024;
byte[] bys = new byte[size];
int fileLen = (int) new File("e:/test/picture.png").length();
int count = fileLen % size == 0 ? fileLen / size : fileLen / size + 1;
for(int i = 0; i < count; i++){
int len = size;
if(fileLen % size != 0 && i == count - 1){
len = fileLen % size;
}
raf.seek(i * size);
byte[] buf = new byte[len];
raf.read(buf);
//封装数据包
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("localhost"), 8888);
ds.send(dp);
}
raf.close();
ds.close();
}
}
图片接收端代码
import java.io.FileOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket; /*
使用UDP编程模拟图片接收端
*/
public class PictureReceiver {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("e:/test/picture1.png");
//指定端口
DatagramSocket ds = new DatagramSocket(8888);
byte[] bys = new byte[64 * 1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
while(true){
ds.receive(dp);
byte[] data = dp.getData();
int len = dp.getLength();
fos.write(data,0,len);
}
}
}
1.5.2 TCP编程
TCP是Transmission Control Protocal的缩写,俗称的TCP/IP中,IP协议用于唯一标识两个主机,而TCP协议用于确保传输完整可靠,它在网络两端各建立一个Socket,从而在通信的两端形成一个虚拟的网络连接,一旦连接建立,就可以在两端进行通信了,而Socket网络通信底层使用的是IO技术
UDP编程与TCP编程的几个区别总结:
1. UDP没有客户端,服务端之分,只有发送端和接收端,两端之间无需建立连接,而在TCP编程中明确地对于客户端和服务端进行了区分
2. 如果客户端指定的IP地址不存在,就会报UnknownHostException异常;而如果是端口号不存在,那么就会报Connection refused异常,在客户端创建套接字对象时需要明确指定两者,不可缺其一,而UDP编程并不会
3. 在UDP编程中,需要给接收端发送一个结束标记让接收端知道何时应该退出循环,而TCP编程由于底层使用的仍然是IO,因此只需要判断是否读到-1或是null就可以了

TCP编程实战:将一个本地文件发送到本机的另一个端口上去
客户端:
import java.io.*;
import java.net.Socket; /*
使用TCP编程模拟将一个文件传输到另一个端口上的客户端
*/
public class TCPClient {
public static void main(String[] args) throws Exception {
//新建一个Socket对象,指定需要发送到的IP地址和端口
Socket socket = new Socket("localhost", 8888);
//新建一个输入流读取本地文件
BufferedReader br = new BufferedReader(new FileReader("e:/test/a.txt"));
//通过Socket对象新建一个输出流,并用转换流进行包装
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
//开始按行读取并写出
String line = null;
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
bw.flush();
}
//关闭资源
bw.close();
os.close();
br.close();
socket.close();
}
}
服务端:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket; /*
TCP编程模拟服务端接收文件
*/
public class TCPServer {
public static void main(String[] args) throws Exception {
//绑定端口
ServerSocket ss = new ServerSocket(8888);
//调用accept方法接收数据,是一个阻塞式方法
Socket socket = ss.accept();
//使用ss创建输入流
InputStream is = socket.getInputStream();
//进行包装
BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedWriter bw = new BufferedWriter(new FileWriter("e:/test/aa.txt"));
String line = null;
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
bw.flush();
}
//关闭资源
is.close();
br.close();
bw.close();
socket.close();
ss.close();
}
}
1.5.3 流的半关闭
场景说明:现在需要对上述代码进行改良,在服务端接收完来自客户端的数据之后,再给客户端发送一个反馈消息,告诉客户端数据接收完毕:
客户端:
import java.io.*;
import java.net.Socket; /*
使用TCP编程模拟将一个文件传输到另一个端口上的客户端
改进:并接收来自服务端的反馈消息
*/
public class TCPClient2 {
public static void main(String[] args) throws Exception {
//新建一个Socket对象,指定需要发送到的IP地址和端口
Socket socket = new Socket("localhost", 8888);
//新建一个输入流读取本地文件
BufferedReader br = new BufferedReader(new FileReader("e:/test/a.txt"));
//通过Socket对象新建一个输出流,并用转换流进行包装
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
//开始按行读取并写出
String line = null;
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
bw.flush();
}
//将流半关闭
socket.shutdownOutput();
//新建一个输入流来接收来自服务端的反馈消息
InputStream is = socket.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
System.out.println(new String(buf,0,len));
//关闭资源
is.close();
bw.close();
os.close();
br.close();
socket.close();
}
}
服务端:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket; /*
TCP编程模拟服务端接收文件
改进:并给客户端发送反馈消息
*/
public class TCPServer2 {
public static void main(String[] args) throws Exception {
//绑定端口
ServerSocket ss = new ServerSocket(8888);
//调用accept方法接收数据,是一个阻塞式方法
Socket socket = ss.accept();
//使用ss创建输入流
InputStream is = socket.getInputStream();
//进行包装
BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedWriter bw = new BufferedWriter(new FileWriter("e:/test/aa.txt"));
String line = null;
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
bw.flush();
} //接收完文件之后,再新建一个输出流告诉客户端文件接收完毕
OutputStream os = socket.getOutputStream();
os.write("文件接收完毕!".getBytes());
//关闭资源
os.close();
is.close();
br.close();
bw.close();
socket.close();
ss.close();
}
}
如果在客户端代码中不添加socket.shutdownOutput();这句代码,会发生两端相互等待的情况,这是因为:客户端将文件发送到了末尾,并不会通过流将最后的null传给服务端,因此进入到了等待状态,而服务端一直没有接收到null值,以为还有数据传送过来,在socket对象没有关闭之前就一直在循环等待接收文件,而shutdownOutput方法相当于在把socket关闭之前,先把由socket对象创建的输出流先关闭了,从而避免了相互等待的情况出现,因此这个又被称为是流的半关闭
大数据学习笔记——Java篇之网络编程基础的更多相关文章
- 大数据学习笔记——Java篇之集合框架(ArrayList)
Java集合框架学习笔记 1. Java集合框架中各接口或子类的继承以及实现关系图: 2. 数组和集合类的区别整理: 数组: 1. 长度是固定的 2. 既可以存放基本数据类型又可以存放引用数据类型 3 ...
- 大数据学习笔记——Java篇之IO
IO学习笔记整理 1. File类 1.1 File对象的三种创建方式: File对象是一个抽象的概念,只有被创建出来之后,文件或文件夹才会真正存在 注意:File对象想要创建成功,它的目录必须存在! ...
- 大数据学习笔记——Java篇之基础知识
Java / 计算机基础知识整理 在进行知识梳理同时也是个人的第一篇技术博客之前,首先祝贺一下,经历了一年左右的学习,从完完全全的计算机小白,现在终于可以做一些产出了!可以说也是颇为感慨,个人认为,学 ...
- javaSE学习笔记(16)---网络编程
javaSE学习笔记(16)---网络编程 基本概念 如今,计算机已经成为人们学习.工作.生活必不可少的工具.我们利用计算机可以和亲朋好友网上聊天,也可以玩网游.发邮件等等,这些功能实现都离不开计算机 ...
- 大数据学习笔记——Linux完整部署篇(实操部分)
Linux环境搭建完整操作流程(包含mysql的安装步骤) 从现在开始,就正式进入到大数据学习的前置工作了,即Linux的学习以及安装,作为运行大数据框架的基础环境,Linux操作系统的重要性自然不言 ...
- 大数据学习笔记之Hadoop(一):Hadoop入门
文章目录 大数据概论 一.大数据概念 二.大数据的特点 三.大数据能干啥? 四.大数据发展前景 五.企业数据部的业务流程分析 六.企业数据部的一般组织结构 Hadoop(入门) 一 从Hadoop框架 ...
- 大数据学习笔记——Hadoop编程实战之HDFS
HDFS基本API的应用(包含IDEA的基本设置) 在上一篇博客中,本人详细地整理了如何从0搭建一个HA模式下的分布式Hadoop平台,那么,在上一篇的基础上,我们终于可以进行编程实操了,同样,在编程 ...
- 大数据学习笔记——Linux基本知识及指令(理论部分)
Linux学习笔记整理 上一篇博客中,我们详细地整理了如何从0部署一套Linux操作系统,那么这一篇就承接上篇文章,我们仔细地把Linux的一些基础知识以及常用指令(包括一小部分高级命令)做一个梳理, ...
- 大数据学习笔记——Hadoop编程实战之Mapreduce
Hadoop编程实战——Mapreduce基本功能实现 此篇博客承接上一篇总结的HDFS编程实战,将会详细地对mapreduce的各种数据分析功能进行一个整理,由于实际工作中并不会过多地涉及原理,因此 ...
随机推荐
- node.js和ionic
1.安装node.js node -v 检测node文件是否安装成功 node --version 检查node版本号 2.Npm node package manager 管理工具 管理模 ...
- 力扣(LeetCode)颠倒二进制位 个人题解
颠倒给定的 32 位无符号整数的二进制位. 示例 1: 输入: 00000010100101000001111010011100 输出: 0011100101111000001010010100000 ...
- three.js使用gpu选取物体并计算交点位置
光线投射法 使用three.js自带的光线投射器(Raycaster)选取物体非常简单,代码如下所示: var raycaster = new THREE.Raycaster(); var mouse ...
- javescript 的 对象
一,定义:对象是JavaScript的一个基本数据类型,是一种复合值,它将很多值(原始值或者其他对象)聚合在一起,可通过名字(name/作为属性名)访问这些值.即属性的无序集合. 关键是name属性名 ...
- 笔记本进入BIOS设置
转眼间,到大三了. 在学习<Red Hat Linux 服务器搭建与管理>这门课时,刚开学第一节,就是虚拟机,但是最烦恼的是我们笔记本电脑的默认设置,它把虚拟化给禁止了. 1,首先,我们需 ...
- 【Flink】Flink基础之WordCount实例(Java与Scala版本)
简述 WordCount(单词计数)作为大数据体系的标准示例,一直是入门的经典案例,下面用java和scala实现Flink的WordCount代码: 采用IDEA + Maven + Flink 环 ...
- Reactor和Proactor模型
背景 前面介绍了I/O多路复用模型,那有了I/O复用,有了epoll已经可以使服务器并发几十万连接的同时,还能维持比较高的TPS,难道还不够吗?比如现在在使用epoll的时候一般都是起个任务,不断的去 ...
- JavaScript笔记二
1.表格 - 在网页中可以通过表格来表示一些格式化的数据 - 表格相关的标签 - <table> 用来创建一个表格 - <tr> 表示表格中的一行 - <th> 表 ...
- Anaconda中启动Python时的错误:UnicodeDecodeError: 'gbk' codec can't decode byte 0xaf in position 553
今天,在Anaconda prompt启动python遇到了如下错误: UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0xaf in positi ...
- /etc/security/limits.conf 详解与配置
目录 一. /etc/security/limits.conf 详解 /etc/security/limits.conf 配置解析 /etc/security/limits.d/ 目录 二. ulim ...