第一章 网络编程入门
1.1 网络通信协议
计算机进行数据传输 需要遵守的规则
UDP协议特点
面向无连接的通信协议 两台计算机进行数据交互不需要建立连接
发送端直接给接收端发送数据 接收端接收到数据也不会给发送端回应
UDP不需要建立连接 消耗资源少 发送速率快 但是每次发送数据不能超过64KB
不能保证数据的完整性
TCP协议特点
面向连接的通讯协议 两天计算机要想进行数据交互必须进行连接
客户端----> 服务端
客户端<---- 服务端
客户端----> 服务端
建立连接 消耗资源多 发送速率慢 但是发送数据无限制 可以保证数据的可靠性
1.2 网络编程三要素
三要素:
协议: 计算机网络通信必须遵守的规则
IP地址: 指互联网协议地址(Internet Prottocol Address),俗称IP;
IP地址是计算机进入到网络中的唯一标识
IPv4: 四个字节大小的二进制数来表示 每个字节用一个十进制数字(0-255)表示, 数字用符号"."分开,如"192.168.1.100";
IPv6: 采用128为地址长度, 每16个字节一组, 分成8组十六进制数, 表示成ABCD:EF01:2345:6789
查看本机IP
ipconfig
监测两台计算机是否能够建立连接
ping 网址/IP
两个特殊的IP地址
127.0.0.1
localhost 本地主机/当前计算机的IP
端口号: 用来表示应用程序, 用两个字节表示的整数, 它的取值范围是 0-65535.
1.3 InetAddress
java.bet.InetAddress
静态方法
static InetAddress getLocalHost(); 返回本地主机
static InetAddress getByName(String host); 在给定主机名的情况下确定主机的 IP 地址
public String getHostName(); 获取此 IP 地址的主机名。
public String getHostAddress(); 返回 IP 地址字符串(以文本表现形式)。
代码演示:
public static void main(String[] args) throws UnknownHostException {
//获取本地主机
InetAddress host = InetAddress.getLocalHost();
System.out.println(host);
String hostName = host.getHostName();
String hostAddress = host.getHostAddress();
System.out.println(hostName);
System.out.println(hostAddress);
System.out.println("---------------------------");
InetAddress byName = InetAddress.getByName("192.169.5.7");
System.out.println(byName);
System.out.println(byName.getHostName());
InetAddress byName1 = InetAddress.getByName("www.baidu.com");
System.out.println(byName1);
}
结果:
DESKTOP-AMHN57C/192.168.5.83
DESKTOP-AMHN57C
192.168.5.83
---------------------------
/192.169.5.7
192-169-5-7-static.despegar.net
www.baidu.com/110.242.68.3
第三章 UDP通信
3.1 发送端(发送端一定要明确指出数据的目的地(ip地址和端口号))
java.net.DatagramSocket
构造方法
public DatagramSocket();
方法
void send(DatagramPacket p); 发送数据包
发送端数据包
java.net.DatagramPacket
构造方法
public datagramPacket(byte[] bytes,int length, InetAddress ip, int port);
用来将长度为 length 的包发送到指定主机上的指定端口号
1. 创建发送端对象
2. 创建数据包对象 封装数据包
3. 调用发送端的send方法 发送数据包
4. 关闭资源
(注: DatagramPacket数据包的作用就如同是“集装箱”,可以将发送端或者接收端的数据封装起来
DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包)
代码演示:
public static void main(String[] args) throws IOException {
// 1. 创建发送端对象
DatagramSocket ds = new DatagramSocket();
// 2. 创建数据包对象 封装数据包
byte[] bytes = "Hello, UDP!".getBytes();
InetAddress ip = InetAddress.getByName("127.0.0.1");
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,9999);
// 3. 调用发送端的send方法 发送数据包
ds.send(dp);
// 4. 关闭资源
ds.close();
}
3.2 接收端
UDP接收端
java.net.DategramSocket
构造方法
public DategramSocket(int port); 创建接收端对象 比并将其绑定到本地主机上的指定接口
方法
void receive(DatagramPacket p); 接收数据包
接收端数据包
java.net.DatagramPacket
构造方法
DatagramPacket(byte[] buf, int length); 用来接收长度为 length 的数据包
方法
InetAddress getAddress(); 获取发送端IP地址
int getLength(); 获取接受数据的长度
int getPort(); 获取发送端断口
1. 创建接收端对象
2. 创建接收端数据包对象
3. 调用接收端的receive接受数据
4. 拆包
5. 关闭资源
代码演示:
public static void main(String[] args) throws IOException {
// 1. 创建接收端对象
DatagramSocket ds = new DatagramSocket(9999);
// 2. 创建接收端数据包对象
byte[] bytes = new byte[1024*64];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
// 3. 调用接收端的receive接受数据
ds.receive(dp);
// 4. 拆包
InetAddress ip = dp.getAddress();
int port = dp.getPort();
int length = dp.getLength();
System.out.println(ip+":"+port+" "+new String(bytes,0,length));
// 5. 关闭资源
ds.close();
}
模拟简单聊天室案例:
代码演示:
(发送端)
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class Test02 {
public static void main(String[] args) throws IOException {
// 1. 创建发送端对象
DatagramSocket ds = new DatagramSocket();
// 2. 创建数据包对象 封装数据包
Scanner sc = new Scanner(System.in);
while(true){
String line = sc.nextLine();
byte[] bytes = line.getBytes();
InetAddress ip = InetAddress.getByName("127.0.0.1");
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,9999);
// 3. 调用发送端的send方法 发送数据包
ds.send(dp);
}
// 4. 关闭资源
// ds.close();
}
}
(接收端)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class Test03 {
public static void main(String[] args) throws IOException {
// 1. 创建接收端对象
DatagramSocket ds = new DatagramSocket(9999);
// 2. 创建接收端数据包对象
while(true){
byte[] bytes = new byte[1024*64];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
// 3. 调用接收端的receive接受数据
ds.receive(dp);
// 4. 拆包
InetAddress ip = dp.getAddress();
int port = dp.getPort();
int length = dp.getLength();
System.out.println(ip+":"+port+" "+new String(bytes,0,length));
}
// 5. 关闭资源
// ds.close();
}
}
结果:
(发送数据):
aaa
bbb
zxcasdqwe
ertdfgcvb
(接收数据):
/127.0.0.1:56333 aaa
/127.0.0.1:56333 bbb
/127.0.0.1:56333 zxcasdqwe
/127.0.0.1:56333 ertdfgcvb
第四章 TCP通信协议
4.1 概述
TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。
两端通信时步骤:
1. 服务端程序,需要事先启动,等待客户端的连接。
2. 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端
在Java中,提供了两个类用于实现TCP通信程序:
客户端:java.net.Socket 类表示。
创建 Socket 对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。
服务端:java.net.ServerSocket 类表示。
创建 ServerSocket 对象,相当于开启一个服务,并等待客户端的连接
4.2 Socket类
Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点
java.net.Socket
构造方法:
Public Socket(String ip, int port); 创建客户端对象 连接服务端(该对象一旦创建,便自动连接服务端,若服务端不存在则报错)
Public Socket(InetAddress ip, int port);
方法:
InputStream getInputStream(); 获取字节输入流
OutputStream getOutputStream(); 获取字节输出流
过程:
1. 创建客户端对象
2. 获取字节输出流对象
3. 向服务端 发送数据
4. 获取字节输入流对象
5. 接收服务端返回的数据
6. 关闭资源
4.3 ServerSocket类
ServerSocket类:这个类实现了服务器套接字,该对象等待通过网络的请求。
java.net.ServerSocket
构造方法:
public ServerSocket(int port); 创建服务端对象 绑定端口(参数port就是端口号)
方法:
Socket accept(); 获取正在连接的客户端对象
过程:
1. 创建服务端对象 绑定端口
2. 调用accept方法 获取正在连接的客户端对象
3. 使用客户端对象获取字节输入流对象
4. 接收客户端发送的数据
5. 使用客户端 获取字节输出流对象
6. 向当前客户端 返回数据
7. 关闭资源
代码演示:
(客户端)
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Test004 {
public static void main(String[] args) throws IOException {
// 1. 创建客户端对象
Socket s = new Socket("127.0.0.1",9999);
// 2. 获取字节输出流对象
OutputStream out = s.getOutputStream();
// 3. 向服务端 发送数据
out.write("你好,连一下呗".getBytes());
System.out.println("-----------------------");
// 4. 获取字节输入流对象
InputStream in = s.getInputStream();
// 5. 接收服务端返回的数据
byte[] bytes = new byte[1024];
int len = in.read(bytes);
System.out.println(new String(bytes,0,len));
// 6. 关闭资源
s.close();
}
}
(服务端)
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Test005 {
public static void main(String[] args) throws IOException {
// 1. 创建服务端对象 绑定端口
ServerSocket ss = new ServerSocket(9999);
// 2. 调用accept方法 获取正在连接的客户端对象(accept方法具有阻塞功能,如果没有客户端连接, 服务端运行时会一直等待)
Socket s = ss.accept();
// 3. 使用客户端 获取字节输入流对象
InputStream in = s.getInputStream();
// 4. 接收客户端发送的数据
byte[] bytes =new byte[1024];
int len = in.read(bytes);
System.out.println(new String(bytes,0,len));
System.out.println("----------------------------------");
// 5. 使用客户端 获取字节输出流对象
OutputStream out = s.getOutputStream();
// 6. 向当前客户端 返回数据
out.write("滚,连你妹呀!!".getBytes());
// 7. 关闭资源
out.close();
in.close();
s.close();
ss.close();
}
}
结果:
(接收端收到的客户端的信息)
你好,连一下呗
----------------------------------
(客户端收到的服务端返回的信息)
-----------------------
滚,连你妹呀!!
第五章 文件上传案例
(文件只上传一次 ,如果想要实现多次上传,就要解决文件名相同的问题; 可以使用线程池(使用多线程)来解决)
5.1 客户端实现
数据源: D:\\2development\\abc\\zhaopian\\mm.jpg
数据目的:服务端
过程:
1. 创建客户端对象 绑定服务端IP和端口
2. 创建文件字节输出流 绑定数据源
3. 获取字节输出流对象
4. 循环读写
5. 获取字节输入流对象
6. 接收服务端返回的"上传成功"
7. 关闭资源
5.2 服务端实现
数据源: 客户端
数据目的: D:\\2development\\abc\\mm.jpg
过程:
1. 创建服务端对象 绑定端口号
2. 调用accept方法 获取正在连接的客户端对象
3. 获取字节输入流 用来接收客户端发送的数据
4. 创建文件字节输出流 绑定数据目的
5. 循环读写
6. 获取字节输出流对象
7. 向客户端返回数据"上传成功"
8. 关闭资源
5.3 代码演示:
(客户端代码)
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Test006 {
public static void main(String[] args) throws IOException {
// 1. 创建客户端对象 绑定服务端IP和端口
Socket s = new Socket("127.0.0.1",6666);
// 2. 创建文件字节输入流 绑定数据源
FileInputStream fis = new FileInputStream("D:\\2development\\abc\\zhaopian\\mm.jpg");
// 3. 获取字节输出流对象
OutputStream out = s.getOutputStream();
// 4. 循环读写
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes))!= -1){
out.write(bytes,0,len);
}
//告知服务器已经写完了(相当于向服务端写过去一个结束标记)
s.shutdownOutput();
System.out.println("--------------接收服务端返回的数据----------------");
// 5. 获取字节输入流对象
InputStream in = s.getInputStream();
// 6. 接收服务端返回的"上传成功"
int length = in.read(bytes);
System.out.println(new String(bytes,0,length));
// 7. 关闭资源
in.close();
out.close();
fis.close();
s.close();
}
}
(服务端代码)
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Test007 {
public static void main(String[] args) throws IOException {
// 1. 创建服务端对象 绑定端口号
ServerSocket ss = new ServerSocket(6666);
// 2. 调用accept方法 获取正在连接的客户端对象
Socket s = ss.accept();
// 3. 获取字节输入流 用来接收客户端发送的数据
InputStream in = s.getInputStream();
// 4. 创建文件字节输出流 绑定数据目的
FileOutputStream fos = new FileOutputStream("D:\\2development\\abc\\mm.jpg");
// 5. 循环读写
byte[] bytes = new byte[1024];
int len = 0;
while((len = in.read(bytes)) != -1){
fos.write(bytes,0,len);
}
System.out.println("--------------向客户端返回数据--------------");
// 6. 获取字节输出流对象
OutputStream out = s.getOutputStream();
// 7. 向客户端返回数据"上传成功"
out.write("上传成功".getBytes());
// 8. 关闭资源
out.close();
in.close();
fos.close();
s.close();
ss.close();
}
}