1 网络通信协议
1.1 IP地址
1.2 端口号
1.3 InetAddress基本使用
在java中,可以使用一个类表示ip地址,这个类叫做InetAddress
static InetAddress getLocalHost(): 获取到本机的ip地址对象。
static InetAddress getByName(String host):根据主机名获取到ip地址对象。
String getHostName(): 获取字符串类型的主机名。
String getHostAddress(): 获取字符串类型的ip地址。
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
/*
在java中,可以使用一个类表示ip地址,这个类叫做InetAddress
static InetAddress getLocalHost(): 获取到本机的ip地址对象。
static InetAddress getByName(String host):根据主机名获取到ip地址对象。
String getHostName(): 获取字符串类型的主机名。
String getHostAddress(): 获取字符串类型的ip地址。
*/
public class Demo01InetAddress {
public static void main(String[] args) throws IOException {
method3();
}
/*
* String getHostName(): 获取字符串类型的主机名。
* String getHostAddress(): 获取字符串类型的ip地址。
*/
public static void method3() throws IOException {
//先获取一个InetAddress对象。
InetAddress address = InetAddress.getLocalHost();
//InetAddress里面封装了ip地址和主机名。
//我们可以通过getHostName和getHostAddress单独获取到ip地址和主机名
String hostName = address.getHostName();
String ip = address.getHostAddress();
//打印
System.out.println("主机名为:" + hostName);
System.out.println("ip地址为:" + ip);
}
/*
* static InetAddress getByName(String host):根据主机名获取到ip地址对象。
*/
public static void method2() throws IOException {
//根据指定的主机名获取到ip地址对象
//如果在网络中有多个相同的主机名,那么只会获取一个。
//这个方法,不仅可以根据主机名获取ip地址对象,也可以根据字符串类型的ip地址去获取。
//参数传递主机名是可以的,如果传递一个ip地址,也是可以的。
InetAddress address = InetAddress.getByName("jn-pc");
System.out.println(address);
}
/*
* static InetAddress getLocalHost(): 获取到本机的ip地址对象。
*/
public static void method1() throws IOException {
//获取到的是本机的ip地址对象
InetAddress address = InetAddress.getLocalHost();
//InetAddress这个对象中不仅封装了ip地址,还封装了主机名。
System.out.println(address);
}
}
2 UDP和TCP协议
2.1 UDP协议
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
特点:
1.面向无连接,传输数据的时候不需要建立连接。
2.传输的数据有大小限制(64k)
3.效率高,不安全。
使用场景:聊天,广播。
2.2 TCP协议
先建立连接,然后传输数据。
特点(了解)
1.面向连接,发送数据前必须建立连接。
2.传输数据没有大小限制。
3.安全,效率低。
使用场景:长传,下载。
2.3 UDP的发送与接收
UDP发送接收流程
Demo01Sender类
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
/*
UDP程序的发送端
发送端需要用到两个类
DatagramPacket:叫做数据报包。 相当于快递的箱子,用来封装要发送的数据。
DatagramSocket:叫做套接字,用来发送数据报包对象。相当于快递员,用来发送数据。
DatagramPacket 构造方法:
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
参数buf:表示要发送的数据,是一个字节数组。
参数length:表示要发送字节数组的几个长度的数据
参数address: 数据要发给谁。 目标接收端的ip地址。
参数port: 接收端程序的端口号。
DatagramSocket 构造方法:
DatagramSocket():使用空参数构造方法创建对象即可。
DatagramSocket 其他方法:
void send(DatagramPacket p): 用来发送数据,参数是一个数据报包对象
void close(): 释放资源
发送端的步骤
1. 准备要发送的数据。
2. 根据要发送的数据封装一个DatagramPacket对象。
3. 创建DatagramSocket对象,用来发送数据。
4. 调用send方法,将数据发送出去。
5. 释放资源。
*/
public class Demo01Sender {
public static void main(String[] args) throws IOException {
//准备要发送的数据。
byte[] bArr = "你好网络编程,I'm coming".getBytes();
int len = bArr.length;
InetAddress address = InetAddress.getByName("127.0.0.1");//ip地址,表示要发给自己。
int port = 9527;
//根据要发送的数据封装一个DatagramPacket对象。
DatagramPacket packet = new DatagramPacket(bArr, len, address, port);
//创建DatagramSocket对象,用来发送数据。
DatagramSocket socket = new DatagramSocket();
//调用send方法,将数据发送出去。
socket.send(packet);
//释放资源。
socket.close();
}
}
Demo02Receiver类
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/*
UDP程序的接收端
接收端同样也需要用到两个类。
DatagramPacket:数据报包。用来封装要接收的数据。快递的箱子。
DatagramSocket:套接字,用来接收数据。 快递员
DatagramPacket构造方法:
DatagramPacket(byte[] buf, int length)
参数buf:表示要使用这个字节数组去接收数据。
参数length:表示要使用这个字节数组的几个长度去接收数据。
DatagramSocket构造方法:
DatagramSocket(int port):参数是一个端口号。 表示的是此接收端程序的端口号。
DatagramPacket其他拆包方法:
byte[] getData():获取保存数据的字节数组
int getLength():获取接收到数据的长度。
InetAddress getAddress():获取发送端的ip地址。
int getPort():获取发送端程序的端口号。
DatagramSocket的其他方法:
void receive(DatagramPacket p):接收方法,可以接收到发送端发送过来的数据。
接收端的步骤:
1. 准备一个字节数组。
2. 创建DatagramPacket对象。
3. 创建DatagramSocket对象,并且才参数位置指明此接收端程序的端口号。
4. 调用DatagramSocket的receive方法,接收数据。
5. 调用DatagramPacket对象的拆包方法,进行拆包。
6. 打印数据。
7. 释放资源
*/
public class Demo02Receiver {
public static void main(String[] args) throws IOException {
//准备一个字节数组。
byte[] bArr = new byte[1024];
//创建DatagramPacket对象,相当于快递的箱子。
DatagramPacket packet = new DatagramPacket(bArr, bArr.length);
//创建DatagramSocket对象,并且才参数位置指明此接收端程序的端口号。
DatagramSocket socket = new DatagramSocket(9527);
//调用DatagramSocket的receive方法,接收数据。
socket.receive(packet);
//调用DatagramPacket对象的拆包方法,进行拆包。
byte[] data = packet.getData();//保存收到数据的字节数组
int len = packet.getLength();//收到数据的长度
InetAddress address = packet.getAddress();//发送端的ip地址
int port = packet.getPort();//发送端的端口号
//打印数据。
System.out.println("接收端收到数据:" + new String(data, 0, len));
System.out.println("数据来自:" + address + ":" + port);
//释放资源
socket.close();
}
}
3 TCP通信
3.1 服务器与客户端
3.2 TCP中的IO技术
3.3 TCP的客户端实现
(插播:
套接字是两台机器间通信的端点。)
TCP程序的客户端(TCP两端分别是客户端和服务器)
在java中可以使用一个类表示客户端,这个类叫做Socket。
Socket的构造方法:
Socket(InetAddress address, int port):使用这个构造方法创建对象时,会尝试着和服务器进行连接。
参数address:目标要连接服务器的ip地址。
参数port:要连接服务器程序的端口号。
Socket的其他方法:
OutputStream getOutputStream():获取字节输出流,用来向服务器发送数据(写数据)。
InputStream getInputStream():获取字节输入流,用来读取服务器发送过来的数据(读数据).
void close(): 释放资源
实现步骤:
1. 创建一个客户端Socket对象,并且在构造方法中传递要连接服务器的ip地址以及端口号。
2. 调用Socket对象的getOutputStream方法,获取到一个输出流,用来向服务器发送数据。
3. 调用输出流的write方法写数据(写数据,其实就是在向服务器发送数据)。
4. 调用Socket对象的getInputStream方法,获取到一个输入流,用来读取服务器发送过来的数据。
5. 调用输入流的read方法,读取数据(接收数据)
6. 释放资源
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class Demo01Client {
public static void main(String[] args) throws IOException {
//创建一个客户端Socket对象,并且在构造方法中传递要连接服务器的ip地址以及端口号。
//创建Socket对象的时候会去和服务器建立连接。如果连接不上就会抛出异常。
//因为TCP协议是可靠的协议,是面向连接的协议,所以必须要建立连接才能进行其他操作。
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 10010);
//调用Socket对象的getOutputStream方法,获取到一个输出流,用来向服务器发送数据。
OutputStream out = socket.getOutputStream();//获取到的这个输出流目的地是服务器,是用来往服务器写数据的。
//调用输出流的write方法写数据(写数据,其实就是在向服务器发送数据)
out.write("你好".getBytes());//把数据写给了服务器。
//调用Socket对象的getInputStream方法,获取到一个输入流,用来读取服务器发送过来的数据。
InputStream in = socket.getInputStream();
//调用输入流的read方法,读取数据(接收数据)
byte[] bArr = new byte[1024];
int len = in.read(bArr);
System.out.println("客户端接收到数据:" + new String(bArr, 0, len));
socket.close();
}
}
3.4 TCP的服务器端实现
tcp程序的服务器端。
在java中可以使用一个类表示服务器,这个类叫做ServerSocket
ServerSocket的构造方法
ServerSocket(int port):参数为此服务器程序的端口号。
ServerSocket的其他方法:
Socket accept(): 监听并获取客户端套接字。(等着客户端的请求,并拿到客户端的套接字信息(里面包含的发送 过来的数据))
服务器端的使用步骤:
1. 创建ServerSocket对象,这个对象表示服务器。
2. 调用ServerSocket对象的accept方法,等待获取客户端的请求,并得到客户端的套接字对象Socket
3. 调用客户端Socket对象的getInputStream用来读取客户端发过来的信息
4. 调用read方法,读取客户端发过来的数据。
5. 调用客户端Socket对象的getOutputStream,用来发送
6. 调用write把数据发给客户端。
7. 释放资源。
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo02Server {
public static void main(String[] args) throws IOException {
//创建ServerSocket对象,这个对象表示服务器。
ServerSocket serverSocket = new ServerSocket(10010);
//调用ServerSocket对象的accept方法,等待获取客户端的请求,并得到客户端的套接字对象Socket
Socket socket = serverSocket.accept();
//调用客户端Socket对象的getInputStream用来读取客户端发过来的信息
InputStream in = socket.getInputStream();
//调用read方法,读取客户端发过来的数据。
byte[] bArr = new byte[1024];
int len = in.read(bArr);
System.out.println("服务器端收到消息:" + new String(bArr, 0, len));
//调用客户端Socket对象的getOutputStream,用来发送
OutputStream out = socket.getOutputStream();
//调用write把数据发给客户端。
out.write("作为服务器的我已经收到了消息,谢谢".getBytes());
serverSocket.close();
}
}
3.5 TCP发送接收流程
4 文件上传案例
4.1 上传案例流程
4.2 上传案例客户端的实现
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
/*
上传案例的客户端。
就是把自己的文件读取出来,然后写入到服务器就可以了。
因为文件的字节比较大,所以需要使用循环读写。
步骤:
1. 创建客户端Socket对象。参数位置给出要连接服务器的信息。
2. 通过Socket对象获取到一个输出流,用来向服务器写数据。
3. 创建一个FileInputStream,用来读取要上传的文件。
4. 开始读写,每读取一个字节数组,就将读取到的内容写入到目的地(服务器)
5. 通过Socket对象获取到一个输入流,用来读取服务器返回过来的数据。
6. 调用read方法读取数据。
7. 释放资源
*/
public class Demo03UploadClient {
public static void main(String[] args) throws IOException {
//创建客户端Socket对象。参数位置给出要连接服务器的信息。
//第一个参数ip地址也可以是字符串类型。
Socket socket = new Socket("127.0.0.1", 10000);
//通过Socket对象获取到一个输出流,用来向服务器写数据。
OutputStream out = socket.getOutputStream();
//创建一个FileInputStream,用来读取要上传的文件。
FileInputStream fis = new FileInputStream("d:\\client\\aa.jpg");
//开始读写,每读取一个字节数组,就将读取到的内容写入到目的地(服务器)
byte[] bArr = new byte[1024];
int len;
while((len = fis.read(bArr)) != -1) {
out.write(bArr, 0, len);
}
//执行到这里表示把文件中的所有的数据都写给了服务器。
//就可以告诉给服务器,我不会再给你写东西。
socket.shutdownOutput();
//释放输入流
fis.close();
//通过Socket对象获取到一个输入流,用来读取服务器返回过来的数据。
InputStream in = socket.getInputStream();
//调用read方法读取数据。
len = in.read(bArr);
System.out.println("客户端收到消息:" + new String(bArr, 0, len));
//释放资源
socket.close();
}
}
4.3 上传案例服务器端的实现
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
/*
上传案例的服务器。
接收客户端发过来的字节数据,每接收到,就把接收到的这些字节数据写入到自己服务器电脑的文件。
步骤:
1. 创建服务器ServerSocket对象,
2. 监听并获取客户端Socket对象。
3. 调用客户端Socket对象的getInputStream,得到输入流,用来读取客户端发过来的字节。
4. 创建FileOutputStream,用来将读取到的数据写入到自己电脑。
5. 开始读取,每读取到数据,就把读取到的数据写入到电脑中。
6. 调用客户端的Socket对象的getOutputStream,得到输入流,用来向客户端发消息。
7. 调用write方法,发送消息。
8. 释放资源。
*/
public class Demo04UploadServer {
public static void main(String[] args) throws IOException {
//创建服务器ServerSocket对象
ServerSocket serverSocket = new ServerSocket(10000);
//监听并获取客户端Socket对象。
Socket socket = serverSocket.accept();
//调用客户端Socket对象的getInputStream,得到输入流,用来读取客户端发过来的字节。
InputStream in = socket.getInputStream();
//创建FileOutputStream,用来将读取到的数据写入到自己电脑。
//FileOutputStream fos = new FileOutputStream("d:\\server\\aa.jpg");
//为了保证文件不会被覆盖掉,一般使用一个唯一的名字。
//FileOutputStream fos = new FileOutputStream("d:\\server\\" + System.currentTimeMillis() + ".jpg");
//有一个类,可以生成一个唯一的字符串。这个类叫做UUID
FileOutputStream fos = new FileOutputStream("d:\\server\\" + UUID.randomUUID().toString() + ".jpg");
//开始读取,每读取到数据,就把读取到的数据写入到电脑中。
byte[] bArr = new byte[1024];
int len;
while((len = in.read(bArr)) != -1) {
//把读取到的数据写入到本机
fos.write(bArr, 0, len);
}
fos.close();
//调用客户端的Socket对象的getOutputStream,得到输入流,用来向客户端发消息。
OutputStream out = socket.getOutputStream();
//调用方法,写给客户端一些数据
out.write("上传成功".getBytes());
//释放资源
serverSocket.close();
}
}
5 多线程上传案例的实现
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/*
多线程上传服务器端代码。
即使多次上传,这个服务器也不会停。
步骤:
1. 创建服务器Socket对象。
2. 监听并获取客户端的socket。
3. 创建一个新的线程,去给这个客户端执行上传操作。
把第2步和第3步放入死循环,保证服务器停不下了。
*/
public class Demo04UploadConcurrentServer {
public static void main(String[] args) throws IOException {
//创建服务器Socket对象。
ServerSocket serverSocket = new ServerSocket(10000);
while(true) {
//监听并获取客户端socket
Socket socket = serverSocket.accept();
//创建一个新的线程,去给这个客户端执行上传操作。
//创建一个Runnable接口实现类对象
Task task = new Task(socket);
//开启新线程执行上传任务
new Thread(task).start();
}
}
}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
/*
线程任务类,里面定义了线程要执行的任务。
线程要执行的任务就是为客户端执行上传的操作
*/
public class Task implements Runnable{
private Socket socket;
public Task(Socket socket) {
this.socket = socket;
}
//在run方法中编写上传的操作。
@Override
public void run() {
try {
//调用客户端Socket对象的getInputStream,得到输入流,用来读取客户端发过来的字节。
InputStream in = socket.getInputStream();
//创建FileOutputStream,用来将读取到的数据写入到自己电脑。
FileOutputStream fos = new FileOutputStream("d:\\server\\" + UUID.randomUUID().toString() + ".jpg");
//开始读取,每读取到数据,就把读取到的数据写入到电脑中。
byte[] bArr = new byte[1024];
int len;
while((len = in.read(bArr)) != -1) {
//把读取到的数据写入到本机
fos.write(bArr, 0, len);
}
fos.close();
//调用客户端的Socket对象的getOutputStream,得到输入流,用来向客户端发消息。
OutputStream out = socket.getOutputStream();
//调用方法,写给客户端一些数据
out.write("上传成功".getBytes());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(插播:
1.
this 和super不能出现在静态方法里.
2.查看自己电脑的ip
cmd中 输入ipconfig 查看本机ip
有一个ip表示本机ip 127.0.0.1
localhost这个单词也可以表示本机
3.如何查看自己电脑和指定电脑是否通畅
ping ip地址
4.
端口号一般1-1024被系统占用,尽量不要动,自己定义的时候要设置在这个范围之外(1025-65535)
5.最重要的:
ip:在网络中对于计算机的标识
端口号: 在计算机中对于应用程序的标识。
6.软件的结构:
c/s: 客户端/服务器。 可以把它看成桌面应用程序。 比如迅雷,微信,QQ。
b/s: 浏览器/服务器。 淘宝,京东,世纪佳缘,百合网,珍爱网..
)