软件结构:
1.C/S结构:Client/Server结构
客户端和服务器结构 (如QQ、迅雷、百度网盘等软件)
2.B/S结构:Browser/Server机构
浏览器和服务器结构 (如谷歌、火狐、IE等浏览器)
两种结构各有优势,但都必须有网络的支持。
网络编程,就是在一定协议下,实现两台计算机的通信的程序。
网络编程三要素:
协议 IP地址 端口号
网络通信协议
1.UDP协议 用户数据报协议
无连接,耗资小,通信效率高,但不能保证数据的完整性:网络直播,qq消息传输
数据被限制在64kb内
2.TCP/IP协议 传输控制协议
面向连接,数据安全:迅雷下载、QQ文件传输、网页浏览
IP地址
互联网协议地址,用来给网络中的计算机设备做唯一的编号
可以将个人电脑=电话,那么IP地址=电话号码
IP地址分类:
IPv4:32位地址长度
IPv6:128位地址长度
常用命令:
ipconfig 查看本机IP地址
ping IP地址 检查网络是否连通
本机IP地址: 127.0.0.1、localhost
端口号
是一个逻辑端口,无法直接看到,可以使用一些软件查看端口号
当我们使用网络软件时,操作系统会为该软件分配一个随机的端口号(或该软件向OS申请一个指定的端口号)
网络通信的本质,是两个进程(应用程序)的通信
仅有IP地址,只能保证数据传输到对方计算机,不能保证传输到该计算机指定进程
使用IP地址+端口号,就可以保证数据准确传输到对方计算机的指定软件(进程/应用程序)上了
端口号由两个字节(即16位)组成,取值范围0-65535
注意:
1. 0-1024端口号不能使用,已被系统分配已知的网络软件
2. 网络软件的端口号不能重复
常用端口号:
1.网络端口 80 www.baidu.com:80为正确网址(默认省略80)
2.数据库 mysql:3306 oracle:1521
3.Tomcat服务器 8080
TCP通信程序
1.客户端:java.net.Socket
创建Socket对象,向服务器发出连接请求,服务器端响应请求,两者建立连接开始通信
2.服务端:java.net.ServerSocket
创建ServerSocket对象,相当于开启一个服务,并等待客户端的连接
通信步骤:
服务器端先启动,客户端发送请求,客户端与服务器端建立逻辑连接。
这个连接中包含一个IO对象,客户端与服务器端可以使用这个IO对象进行通信。
通信的数据不仅仅是字符,所以此IO对象是字节流对象。
注意:
1.服务器同时和多个客户端进行交互,服务器必须明确是和哪个客户端进行的交互
在服务器端有accept方法,可以获取请求的客户端对象
2.服务器同时和多个客户端进行交互,需要使用多个IO对象
服务器没有IO流,可以获取请求的客户端对象Socket,利用客户端Socket提供的IO流和客户端进行交互
即:服务器使用客户端的流和客户端进行交互
TCP通信的客户端
java.net.Socket 实现客户端套接字
套接字Socket:两台机器间通信的端点,包含了IP地址和端口的网络单位(Socket可以理解为插座)
构造方法:
Socket(String host,int port) 创建了一个流套接字并将其连接到指定主机的指定端口号
参数:
String host: 服务器主机的名称/服务器的IP地址
int port: 服务器的端口号
成员方法:
OutputStream getOutputStream() 返回此套接字的(字节)输出流
InputStream getInputStream() 返回此套接字的(字节)输入流
void close() 关闭此套接字
实现步骤:
1.创建客户端对象Socket,构造方法绑定服务器的IP地址和端口号
2.使用Socket对象中的getOutputStream()获取网络字节输出流OutputStream对象
3.使用网络字节输出流OutputStream对象的write方法,给服务器发送数据
4.使用Socket对象中的getInputStream()获取网络字节输入流OutInStream对象
5.使用网络字节输入流InputStream对象的read方法,读取服务器回写的数据
6.释放资源(Socket)
注意:
1.客户端和服务器端进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象
2.当我们创建客户端对象Socket时,就会去请求服务器和服务器经过3次握手建立连接通路
若服务器未启动,会抛出异常
若服务器已启动,就可以进行交互
TCP通信的服务器端
java.net.ServerSocket 实现服务器套接字
构造方法:
ServerSocket(int port) 创建绑定到特定端口的服务器套接字
服务器端必须明确是哪个客户端请求的服务器
故可以使用accept方法获取到请求的客户端对象
成员方法:
Socket accept() 侦听并接受到此套接字的连接
实现步骤:
1.创建服务器对象Socket,向系统要指定的端口号
2.使用ServerSocket对象中的accept方法,获取请求的客户端对象Socket
3.使用Socket对象中的getInputStream()获取网络字节输入流OutInStream对象
4.使用网络字节输入流InputStream对象的read方法,读取客户端发送的数据
5.使用Socket对象中的getOutputStream()获取网络字节输出流OutputStream对象
6.使用网络字节输出流OutputStream对象的write方法,给客户端回写数据
7.释放资源(Socket,ServerSocket)
注意:客户端上传文件时:
bis.read(bytes) 读取本地文件,读到结束标记后并不会把结束标记传输给服务器
故服务器接收此文件后,保存到服务器端时,因为没有结束标记,会陷入阻塞
解决方法:
客户端上传完文件后,给服务器添加一个结束标记
void shutdownOutput():
对于TCP套接字,任何以前写入的数据都将被发送,并且加上一个TCP的正常连接终止序列
//文件上传服务器:
//客户端:
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 6666);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("F:\\考研\\沉迷学习.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
socket.shutdownOutput();//注意:必须增添文件结束符
System.out.println("客户端发送完毕");
byte[] by = new byte[1024];
InputStream is = socket.getInputStream();
len = is.read(by);
System.out.println(new String(by, 0, len));
bis.close();
socket.close();
}
}
/*
服务器端:
数据源:客户端
目的地:11-Net\\1.jpg
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(6666);
while (true) {
Socket socket = serverSocket.accept();//若写入try中,会无限创建线程,导致死机
/*
多线程提高效率
有一个客户端上传,就开启一个线程
*/
new Thread(new Runnable() {
@Override
public void run() {
try {
String fileName = "itcast" + System.currentTimeMillis() + new Random().nextInt(99999) + ".jpg";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("11_Net\\" + fileName));
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
System.out.println("服务器已收到");
byte[] bytes = new byte[1024];
int len = 0;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
System.out.println("服务器保存完毕");
socket.getOutputStream().write("告诉客户端文件已收到".getBytes());
bos.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
// serverSocket.close()
}
}