一、网络编程三要素
1、IP地址
- 设备在网络中的地址,是唯一标识
2、端口
- 应用程序在设备中的唯一标识
3、协议
- 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议
二、IP地址
1、含义
- IP地址,全称为
Internet Protocol Address
,网络协议地址。是分配给上网设备的数字标签。 - 常见的IP分类有ipv4和ipv6
2、实践--终端ping网址
- 在终端输入
ping www.itheima.com
的过程解析
3、分类
ipv4:32bit来表示
- 问题:ipv4能分配的地址数量最多为256的四次方个,约为42亿,数量逐渐不够使用
ipv6:128bit来表示
4、相关命令(Mac)
-
查看本机的IP地址
ifconfig
ifconfig | grep net
用管道符号+grep命令来过滤一下,更方便查看
-
检查网络是否连通(还可以确定域名的IP地址)
ping IP地址
5、特殊IP
127.0.0.1
:回送地址,本地回环地址。可以代表本机的IP地址,一般用来测试使用
6、Java中的InetAddress类
6.1、含义
- 表示IP地址
6.2、常用方法
static InetAddress getByName("String host")
:通过主机名获取InetAdress对象,host可以是主机名,也可以是IP地址String getHostName()
:获取主机名String getHostAddress()
:获取IP地址
6.3、关于Mac查看和修改主机名和计算机名
https://www.jianshu.com/p/dbf2fa105f26
三、端口
1、含义
- 应用程序在设备中的唯一表示
2、端口号
- 用两个字节表示的整数来标识。范围0~25535
- 0~1023之间的端口号常用于一些知名的网络服务或应用,我们自己使用1024及以上
3、注意
- 一个端口号只能被一个应用程序来使用
四、协议
1、UDP协议
-
UDP(User Datagram Protocol)用户数据报协议
-
面向无连接:只管发送,不必先建立连接,都可以发送成功。如果两者已经连接,就能成功接收;
-
特点
- 速度快
- 大小限制:最大为64K
- 数据不安全,易丢失
-
常见场景:音视频、普通数据
2、TCP协议
- TCP(Transmission Control Protocol)传输控制协议
- 面向连接:先保证连接已经建立,才传输数据
- 特点
- 速度慢
- 没有大小限制
- 数据安全
- 常用场景:聊天
五、UDP通信程序
1、发送端
- 过程图示
- 代码实现
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1.找码头
DatagramSocket ds = new DatagramSocket();
//2.打包数据
String message = "你好哇,李婷婷!";
byte[] bytes = message.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);
//3.发送数据
ds.send(dp);
//4.释放资源
ds.close();
}
}
2、接收端
- 过程图示
- 代码实现
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.找码头 ---表示从10000端口号接收数据,否则就是从随机端口接收数据
DatagramSocket ds = new DatagramSocket(10000);
//2.创建包
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//3.接受包
ds.receive(dp);
//4.打开包得到数据
byte[] data = dp.getData();
System.out.println(new String(data));
//5.释放资源
ds.close();
}
}
3、实现通信
- 先运行接收端,保证建立了连接。
- 再运行发送端,发送数据
- 检查服务端,确实收到了数据
4、注意
- 如果接收端没有收到数据,就会死等(阻塞)。可以在接收前后加上输出语句来验证
- 新数组接收到的数据中,如果不能填满,会包含空格,可以使用getLength()来获取数据的长度
其实,数组data是多余的,直接用bytes也可以得到数据
5、UDP三种通信方式
5.1、单播:
- 一对一发送
- 之前写的代码就是单播通信
5.2、组播
- 一对多发送,但是多个接收端要是一组的
- 代码实现
组播地址:244.0.0.0 ~ 244.255.255.255 。其中244.0.0.0 ~ 244.0.0.255是预留的组播地址
5.3、广播
- 一对所有发送
- 代码实现
六、TCP通信程序
1、TCP通信原理
-
TCP通信协议是一种可靠的网络协议,所以在通信两端各建立一个Socket对象
-
通信之前,要保证建立连接
-
通过socket产生IO流来进行通信
2、TCP发送数据的步骤
①、创建客户端Socket对象,与指定的服务端连接
②、获取输出流,写出数据
③、释放资源
- 代码实现如下
public class ClientDemo {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 10000);
OutputStream os = socket.getOutputStream();
os.write("xian".getBytes());
os.close();
socket.close();
}
}
//注意:此时如果我们运行,是会报异常ConnectException,因为无法和接收端建立连接
3、TCP接受数据
①、创建服务端Socket对象(ServerSocket)
②、监听客户端,返回一个Socket对象
③、获取输入流,读数据,把数据显示在控制台
④、释放资源
- 代码实现
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
System.out.println(111);
Socket accept = ss.accept();//等待客户端来进行连接,一直等待
System.out.println(222);
//复习
InputStream is = accept.getInputStream();
int b;
while ((b = is.read() )!= -1){
System.out.println((char) b);
}
is.close();
ss.close();
}
}
4、原理分析
- 需要先运行服务端,服务端会执行到
ss.accept()
处等待客户端连接 - 客户端连接,发送数据
- 服务端接受收据
注意
- accept()方法是阻塞的,作用:等待客户端连接
- 客户端连接服务器通过:三次握手
下面的类比就尼玛离谱,公平打在有才上
- 针对客户端,往外写,用输出流;针对服务端,往里读,用输入流
- read()方法是阻塞的
os.close()
会附带一个结束标记,来让read结束socket.close()
关闭连接通过:四次挥手
5、练习一
客户端:发送数据,接受服务端反馈
服务端:接收数据,给出反馈
客户端代码
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建socket对象
Socket socket = new Socket("127.0.0.1", 10086);
//获取输出流,写出数据
OutputStream os = socket.getOutputStream();
os.write("hello".getBytes());
socket.shutdownOutput();//关闭输出流,写一个结束标记给接收端,不会关闭socket
//获取输入流,读入数据
/*
InputStream is = socket.getInputStream();
int b;
while ((b = is.read()) != -1){
System.out.println((char) b);
}
*/
//因为接受的是中文,用字节流会乱码,socket又没有字符流,--->用缓冲流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//关闭资源
br.close();
os.close();
socket.close();
}
}
服务端代码
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建socket对象
ServerSocket ss = new ServerSocket(10086);
//监听客户端,返回一个Socket对象
Socket accept = ss.accept();
//获取输入流,读入数据
InputStream is = accept.getInputStream();
int b;
while ((b = is.read()) != -1){
System.out.println((char) b);
}
//获取输出流,写出数据
/*OutputStream os = accept.getOutputStream();
os.write("你谁啊".getBytes());*/
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("你谁啊?");
//关闭资源
bw.close();
is.close();
ss.close();
}
}
6、练习二
客户端:将文件上传到服务器,接受服务器的反馈
服务器:接受客户端上传的文件,上传完毕后给出反馈
客户端代码
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建socket
Socket socket = new Socket("127.0.0.1", 10086);
//本地流,读取本地文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("heima/ClientDir/java图标.jpg"));
//网络中的流,写到服务器
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
int b;
while ((b = bis.read()) != -1){
bos.write(b);
}
socket.shutdownOutput();//给服务器一个结束标记,表名传输完毕
//获取服务端数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//关闭资源
socket.close();
bis.close();
}
}
服务端代码
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建socket
ServerSocket ss = new ServerSocket(10086);
//等待连接
Socket accept = ss.accept();
//网络中的流,读取客户端数据
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//本地的流,持久化
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("heima/ServerDir/copy.jpg"));
//读取,持久化到本地
int b;
while ((b = bis.read()) != -1){
bos.write(b);
}
//发送反馈信息
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("上传成功");
bw.newLine();
bw.flush();
//关闭资源
ss.close();
accept.close();//网络中的流,随着socket的关闭也会关闭
bos.close();
}
}