服务器就是一台配置很高的电脑
优点:不需要下载客户端,使用起来非常方便。
缺点:用户体验比较差
缺点:需要下载客户端,而且每一次要更新内容的时候,都要更新客户端,甚至要重新下载,非常麻烦。
优点:画面非常精美,用户体验比较好。
设备在网络中的唯一标识
程序在设备中的唯一标识
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。常见的协议有 UDP协议 和 TCP协议
网络通讯协议,数据在网络中进行传输
需要遵守协议,不同的协议,带来的效果不同
IP(Internet Protocol):全称 【互联网协议地址】,是分配给上网设备的唯一标志。
IP地址形式:
方法 | 说明 |
---|---|
getByName | 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址 |
getHostName | 获取主机名 |
getHostAddress | 获取IP |
//1.获取一个IP地址(在网络中计算机的对象)
InetAddress address = InetAddress.getByName("127.0.0.1");
//2.获取主机名获取ip地址
//细节:如果能获取到主机名返回的就是主机名
//但是如果有的情况下,获取不到,返回的就是ip地址
String hostName = address.getHostName();
System.out.println(hostName);
//3.获取IP
String ip = address.getHostAddress();
System.out.println(ip);
端口:应用程序在设备中唯一的标识。
端口号:用两个字节表示的整数,它的取值范围是0~65535。
其中0~1023之间的端口号用于一些知名的网络服务或者应用。
我们自己使用1024以上的端口号就可以了。
常见的端口号
注意:写代码的时候, 注意端口绑定, 不要出现端口冲突
用户数据报协议(User Datagram Protocol)
UDP是面向无连接通信协议。
速度快,有传输大小限制一次最多发送64K,数据不安全,易丢失数据
传输控制协议TCP(Transmission Control Protocol)
TCP协议是面向连接的通信协议。
速度慢,没有大小限制,数据安全。
1 创建发送端对象 : DatagramSocket ds = new DatagramSocket();
2 创建数据包 : DatagramPacket dp = new DatagramPacket(字节数组, 数据个数, 接收端IP, 接收端端口);
3 发送数据 : ds.send(dp);
4 释放资源 : ds.close();
public static void main(String[] args) throws IOException {
/*
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
参数1: 将传输的数据, 转换为字节, 并存入一个数组
参数2: 数组的长度
参数3: InetAddress(IP对象)
参数4: 端口号
*/
Scanner sc = new Scanner(System.in);
//客户端搭建码头
DatagramSocket socket = new DatagramSocket();
while (true){
//准备要发的数据
System.out.println("请输入:");
String s = sc.nextLine();
//当输入 886 程序停止
if (s.equals("886")){
break;
}
byte[] bytes = s.getBytes();
//将需要发的数据打包
DatagramPacket packet = new DatagramPacket(bytes, bytes.length,
InetAddress.getByName("192.168.11.50"),9898);
//发送数据
socket.send(packet);
}
//关流
socket.close();
1 创建接收端对象 : DatagramSocket ds = new DatagramSocket(端口);
2 创建数据包 : DatagramPacket dp = new DatagramPacket(字节数组, 数组的长度);
3 接收数据 : ds.receive(dp);
4 使用接收的数据 : System.out.println(new String(bys, 0, dp.getLength()));
5 释放资源 : ds.close();
public static void main(String[] args) throws IOException {
//服务端搭建码头
DatagramSocket socket = new DatagramSocket(6789);
while (true){
//准备一个接收数据的包裹
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
//接收数据
socket.receive(packet);
//拆包裹
byte[] data = packet.getData();
String s = new String(data, 0, packet.getLength());
String hostAddress = packet.getAddress().getHostAddress();
System.out.println("来自"+hostAddress+"的信息:"+s);
}
/*
//关流
socket.close();
*/
}
Java中的 TCP 通信
方法名 | 说明 |
---|---|
Socket(InetAddress address,int port) | 创建流套接字并将其连接到指定IP指定端口号 |
Socket(String host, int port) | 创建流套接字并将其连接到指定主机上的指定端口号 |
方法名 | 说明 |
---|---|
InputStream getInputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象(Socket)
//Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号
Socket s = new Socket("127.0.0.1",10000);
//获取输出流,写数据
//OutputStream getOutputStream() 返回此套接字的输出流
OutputStream os = s.getOutputStream();
os.write("hello,tcp,我来了".getBytes());
//释放资源
os.close();
s.close();
}
}
方法名 | 说明 |
---|---|
ServletSocket(int port) | 创建绑定到指定端口的服务器套接字 |
方法名 | 说明 |
---|---|
Socket accept() | 监听要连接到此的套接字并接受它 |
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建服务器端的Socket对象(ServerSocket)
//ServerSocket(int port) 创建绑定到指定端口的服务器套接字
ServerSocket ss = new ServerSocket(10000);
//Socket accept() 侦听要连接到此套接字并接受它
Socket s = ss.accept();
//获取输入流,读数据,并把数据显示在控制台
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
String data = new String(bys,0,len);
System.out.println("数据是:" + data);
//释放资源
s.close();
ss.close();
}
}
客户端:数据来自于本地文件,接收服务器反馈
服务器:接收到的数据写入本地文件,给出反馈
方法名 | 说明 |
---|---|
void shutdownInput() | 将此套接字的输入流放置在“流的末尾” |
void shutdownOutput() | 禁止用此套接字的输出流 |
UUID. randomUUID() | 生成随机的文件名 |
import java.io.*;
import java.net.Socket;
public class Client02 {
public static void main(String[] args) throws IOException {
//创建Socket对象指定ip和端口(向服务端发起请求)
Socket socket = new Socket("127.0.0.1",6789);
//使用socket对象获取传输数据的流对象
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
//将字节流转换为字符流(读写中文)
BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
//创建本地文件对象关联文件
File file = new File("D:\\javawork\\熊宝宝.jpg");
//写出文件名到服务端
bw.write(file.getName());
bw.newLine();
bw.flush();
//读取确认信息
String state = br.readLine();
if (state.equals("ok")){
//开始上传,创建本地字节输入流
FileInputStream fis = new FileInputStream(file);
byte[] bys = new byte[8192];
int len;
while ((len = fis.read(bys)) != -1){
os.write(bys,0,len);
}
fis.close();
//关闭写出的流对象,理解为写出结束标志
socket.shutdownOutput();
}
//读取成功上传信息
System.out.println(br.readLine());
//关流
bw.close();
br.close();
socket.close();
}
}
import java.io.*;
import java.net.Socket;
import java.util.UUID;
public class SubmitFileTask implements Runnable{
private Socket socket;
public SubmitFileTask(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//使用socket对象获取传输数据的流对象
try {
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
//将流对象转换为字符流(读写中文)
BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
//读取客服端发送的文件名
String fileName = br.readLine();
File file = new File("D:\\", UUID.randomUUID().toString()+fileName);
//回写确认信息
bw.write("ok");
bw.newLine();
bw.flush();
//创建本地输出流
FileOutputStream fos = new FileOutputStream(file);
byte[] bys = new byte[8192];
int len;
while ((len = is.read(bys)) != -1){
fos.write(bys,0,len);
}
fos.close();
//回写上传成功
bw.write("上传成功");
bw.newLine();
bw.flush();
//关流
bw.close();
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Server02 {
public static void main(String[] args) throws IOException {
//创建ServerSocket对象指定端口号
ServerSocket serverSocket = new ServerSocket(6789);
ThreadPoolExecutor pool = new ThreadPoolExecutor(
2,
5,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
while (true) {
//调用accept方法响应请求,得到Socket对象
Socket socket = serverSocket.accept();
//重点:将上传的任务交给线程池中的对象处理
pool.submit(new SubmitFileTask(socket));
}
}
}