网络基础
网络
概念:两台设备之间通过网络实现数据传输
网络通信:将数据通过网络从一台设备传输到另一台设备
Java.net包下提供了一系列的类或接口
IP地址
概念:用于唯一标识网络中的每台计算机
查看IP地址:ipconfig
IP地址的表示形式:点分十进制,xx.xx.xx.xx
每个十进制数的范围:0 - 255
IP地址的组成 = 网络地址 + 主机地址 ; 例如:192.168.16.96
IPv6是互联网工程任务组设计的用于替代IPv4的下一代IP协议
域名
为了方便记忆,解决记ip的困难
概念:将IP地址映射成域名(HTTP协议)
端口
概念:用于标识计算机上某个特定的网络程序
标识形式:以整数形式,范围0-65535
0-1024已被占用:如ssh 22,ftp 21,http 80
常见网络程序端口号:
- tomcat:8080
- mysql:3306
- oracle:1521
- sqlserver:1443
网络通讯协议
TCP/IP (传输控制协议/因特网协议)
是Internet最基本的协议,由网络层的IP协议和传输层的TCP协议组成的
TCP 和 UDP
TCP协议:
- 使用TCP协议前,需要先建立TCP连接,形成传输数据通道
- 传输前,采用三次握手方式,是可靠传输
- A:发送连接请求
- B:收到连接请求,确认连接请求
- A:确认连接请求,建立连接
- TCP协议进行通信的两个应用进程:客户端,服务端
- 传输完毕,需释放已建立的链接,效率低
UDP协议:
- 将数据,源,目的封装成数据包,不需要建立连接
- 每个数据的大小限制在64k内
- 因无需连接,所以是不可靠传输
- 发送数据结束时无需释放资源,速度快
InetAddress类
相关方法
- 获取本机InetAddress对象:getLocalHost ( )(不可new ,直接使用方法获取)
- 根据指定主机名/域名获取IP地址对象:getByName( )
- 获取本机InetAddress对象的主机名:getHostName( )
- 获取本机InetAddress对象的地址:getHostAddress( )
Socket
基本介绍:
套接字(Socket),开发网络应用程序被广泛使用,以至于成为事实上的标准
通信的两端都要有Socket,是两台机器间通信的端点
网络通信其实就是Socket之间的通信
Socket允许程序把网络连接当成一个流,数据在Socket之间通过IO传输
一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
场景1:client向服务端发送一个信息
服务端
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) throws IOException {
// 在本机的9999端口监听,等待连接
ServerSocket serverSocket = new ServerSocket(9999);
// 当没有客户端连接9999端口时,程序阻塞,等待连接
System.out.println("server 9999 listening");
Socket socket = serverSocket.accept();
// 打印从client接收到的信息
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLine = 0;
while ((readLine = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLine));
}
// 关闭流
inputStream.close();
socket.close();
serverSocket.close();
System.out.println("server exit");
}
}
客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class MainClient {
public static void main(String[] args) throws IOException, InterruptedException {
// 连接本机的9999端口号
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("client 9999 start,server connet");
// 发送信息到服务端
OutputStream outputStream = socket.getOutputStream();
outputStream.write("from client : hello server ".getBytes());
// 关闭流
outputStream.close();
socket.close();
System.out.println("client exit");
}
}
场景2:字节流互发信息
互发信息必须有一个输出完毕和接收完毕的标记,否则会程序无法知道某方是否已经结束输出而导致阻塞
设置结束标记,表示已经接受完毕:
socket.shutdownInput();
设置结束标记,表示已经输出完毕:
socket.shutdownOutput();
服务端
package Socket2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) throws IOException {
// 在本机的9999端口监听,等待连接
ServerSocket serverSocket = new ServerSocket(9999);
// 当没有客户端连接9999端口时,程序阻塞,等待连接
System.out.println("server 9999 listening");
Socket socket = serverSocket.accept();
// 打印从client接收到的信息
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLine = 0;
while ((readLine = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLine));
}
// 设置结束标记,表示已经接收完毕
socket.shutdownInput();
// 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("from server : hello client ".getBytes());
// 设置结束标记,表示已经输出完毕
socket.shutdownOutput();
// 关闭流
inputStream.close();
outputStream.close();
socket.close();
serverSocket.close();
System.out.println("server exit");
}
}
客户端
package Socket2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class MainClient {
public static void main(String[] args) throws IOException, InterruptedException {
// 连接本机的9999端口号
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("client 9999 start,server connet");
// 发送信息到服务端
OutputStream outputStream = socket.getOutputStream();
outputStream.write("from client : hello server ".getBytes());
// 设置结束标记,表示已经输出完毕
socket.shutdownOutput();
// 打印从服务器接收到的信息
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLine = 0;
while ((readLine = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLine));
}
// 设置结束标记,表示已经接收完毕
socket.shutdownInput();
// 关闭流
outputStream.close();
inputStream.close();
socket.close();
System.out.println("client exit");
}
}
场景3:图片通过socket从客户端上传保存到服务端某个指定目录
Inputstream转换为byte[ ]的方法类
package Scoker3;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class ToByteArray {
// 将输入流转换成byte[],既可以将文件读入到byte[]
public static byte[ ] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 创建输出流对象
byte[] buffer = new byte[1024*4]; // 创建字节数组
int len = 0;
while ((len = input.read(buffer))!= -1) { // 循环读取
bos.write(buffer, 0, len); // 将读取到的数据,写入bos
}
byte[] array = bos.toByteArray();// 将bos转换成字节数组
bos.close();
return array;
}
}
思路:Server
- 创建 BufferedInputStream bis 套接 socket.getInputStream
- 创建 byte[ ] bs 读取 bis
- 创建 BufferedOutputStream bos 套接 FileOutputStream
- 将 bs 写入 bos,写入磁盘
package Scoker3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class PictureServer {
public static void main(String[] args) throws IOException {
// Server监听8888
ServerSocket serverSocket = new ServerSocket(8888);
// Server等待连接
Socket socket = serverSocket.accept();
// 获取到客户端发送的数据
// 通过socket获取输入流,并缓冲
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
// 将bis转换成byte[]
byte[] b = ToByteArray.toByteArray(bis);
// 指定拷贝路径
String copyFilePath = "D:\\test\\test2.jpg";
// 创建填入路径的 FileOutputStream,并使用bos缓冲
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(copyFilePath));
bos.write(b);
// 关闭相关流
bos.close();
bis.close();
socket.close();
serverSocket.close();
}
}
思路:Client
- 创建 BufferedInputStream bis 套接jpg的 FileInputStream fis
- 创建 byte[ ] bs 读取 bis
- 创建 BufferedOutputStream bos 套接 socket.getOutputStream
- 将 bs 写入 bos ,发送给服务端
package Scoker3;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class PictureClient {
public static void main(String[] args) throws IOException {
// 连接服务端8888
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
// 创建指定图片的FileInputStream,并使用BufferedInputStream bis 套接
String filePath = "D:\\test\\test.jpg";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
// 将缓冲的数据bis 转换成为 byte[] b
byte[] b = ToByteArray.toByteArray(bis);
// 通过socket获取到输出流,使用BufferedOutputStream bos 套接,将b数据发送给服务器
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
// 将文件对应的字节数组的内容,写入到数据通道
bos.write(b);
socket.shutdownOutput();// 设置了写入数据结束标记
// 关闭相关流
bis.close();
bos.close();
socket.close();
}
}
场景4:字符流互发信息
字节流读取为字符流
- 使用InputstreamStreamReader 将 InputStream 转化为字符并指定字符集
- 再使用BufferReader 套接 InputstreamStreamReader 缓冲
- 最后使用char[ ] 读取BufferReader
字符流输出为字节流
// BufferWriter --》 OutputStreamWriter --》 OutputStream
服务端
package Socket4;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerHomework {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
// BufferReader --》 InputstreamStreamReader --》 InputStream
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
char[] chars = new char[1024];
int len;
while ((len = br.read(chars))!= -1){
System.out.println(new String(chars,0,len));
}
// 关闭相关流
}
}
客户端
package Socket4;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Scanner;
public class ClientHomework {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),8888);
Scanner scanner = new Scanner(System.in);
String ask = scanner.nextLine();
// BufferWriter --》 OutputStreamWriter --》 OutputStream
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(ask);
bw.newLine();
bw.flush();
socket.shutdownOutput();
// 关闭相关流
}
}
netstat指令
netstat -an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况
netstat -an|more 可以分页显示
说明:
Listening 表示某个端口在监听
如果有一个外部程序连接到该端口,就坏显示一条连接信息
TCP冷知识
当客户端连接到服务器后,实际上客户端也是通过一个端口和服务端进行通讯的,这个端口是TCP/IP分配的,是不确定的,随机的