问题遇到的现象和发生背景
我最近遇到一个问题,就是我学到TCP通信的时候,假如,我作为客户端发送文件给服务器的时候,如果这个文件是一个.jpg的照片,那么我就得在服务器的文件保存路径的末尾加上.jpg 。这样不就变成面向结果编程了嘛?因为我客服端发送的文件是随机格式的,那么服务端应该怎么区别并接收不同类型的文件呢?
问题相关代码,请勿粘贴截图
这是客户端的代码
import java.net.Socket;
import java.io.*;
// (主线程负责发消息,子线程负责收消息)
public class Client{
public static void main(String[] args) {
try {
System.out.println("====客户端启动===");
Socket socket = new Socket("127.0.0.1", 9998);
new ClientThread(socket).start();//新的线程 这个线程用于消息的接收
//1.先将磁盘中的文件读到内存中来 (使用 字节输入流)
InputStream f=new FileInputStream("E:\\Documets\\Desktop\\123.jpg");
BufferedInputStream br=new BufferedInputStream(f); //包装成字节缓存输入流 传送速度快
//2.将内存中文件数据 发送到网络介质上 (使用字节输出流)
OutputStream os = socket.getOutputStream(); //定义发送管道
PrintStream ps = new PrintStream(os); //包装成打印流 速度更快!!!
byte[] buffer=new byte[8192];
int len;
while ((len = br.read(buffer)) != -1) { //通过 缓存字节输入流 接收字节到 buffer中去 并记录数组中的长度len
ps.write(buffer, 0, len); //将buffer中的字节 通过打印流 发送到网络介质中去
}
ps.flush();
socket.shutdownOutput(); //关闭io 而不关闭管道!
System.out.println("文件发给服务器成功!");
// 关闭资源。
//socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
这是 客户端 子线程的的代码
import java.io.*;
import java.net.Socket;
//这个线程类 作为 接收客户端读服务器发来的消息
public class ClientThread extends Thread {//线程类 要继承Thread 或者实现 Runnable 接口
private Socket socket; //用来存套接字
public ClientThread (Socket socket){ //构造方法,用来接收 与服务器连接的管道对管道进行读操作
this.socket = socket;
}
@Override
public void run() {//重写run方法
try {
//1.定义 字节输入流 从网络介质中获取数据存入内存中
InputStream is=socket.getInputStream();
BufferedInputStream br=new BufferedInputStream(is); //包装成字节缓存输入流 传送速度快
//2. 定义 打印流将文件数据从内存中写入磁盘
File file=new File("E:\\Documets\\Desktop\\客户\\服务器发来的.jpg"); //选择保存路径
PrintStream ps = new PrintStream(file);
byte[] buffer=new byte[8192];
int len;
while( (len= br.read(buffer))!=-1 ){
ps.write(buffer,0,len); //将文件写入上面的文件路径中去
}
ps.flush();
System.out.println("接收来自服务器的文件成功!");
} catch (Exception e) {
System.out.println("与服务器断开连接!");
}
}
}
这是 服务器的代码
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
//使用两个线程 主线程 用于将连接过来的套接字 添加到集合 代表当前在线的人数
public class Server {
/*创建一个Socket的list集合 用来装套接字 Socket=(IP地址:端口号) */
public static final List<Socket> onLineSockets = new ArrayList<>(); //当客户端连接上服务器的时候,就将客户端的套接字存入集合中
public static void main(String[] args) {
try {
System.out.println("===服务端启动成功===");
// 1、注册端口
ServerSocket serverSocket = new ServerSocket(9998);
// a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。
while (true) {
// 2、每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+ "上线了!");
//这里可以加上日志框架 打印日志
onLineSockets.add(socket);// 把当前客户端管道Socket加入到在线集合中去
// 3、开始创建独立线程处理socket
new ServerThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这是服务器子线程的代码
```java
import java.io.*;
import java.net.Socket;
//创建线程类 本类用于数据的发送
public class ServerThread extends Thread{
private Socket socket;
public ServerThread (Socket socket) {
this.socket = socket;
}
@Override
public void run() { //重写run方法
try {
//1. 定义字节输入流,用于将网络介质上的文件数据 输入到内存(接收来自某一客户的文件数据)
InputStream is=socket.getInputStream();
BufferedInputStream br=new BufferedInputStream(is); //包装成字节缓存输入流 传送速度快
//2. 定义 打印流将文件数据从内存中写入磁盘 (接收来自客户端的文件 先存到服务器的磁盘下面)
File file=new File("E:\\Documets\\Desktop\\服务器\\客户端发来的123.jpg"); //服务器的保存路径
PrintStream ps0 = new PrintStream(file);
byte[] buffer=new byte[8192];
int len;
while((len= br.read(buffer))!=-1){
ps0.write(buffer ,0 ,len);
ps0.flush();
}
socket.shutdownInput();
System.out.println("接收来自 "+socket.getRemoteSocketAddress()+ "的文件成功!\n");
//将文件发给所有人
sendFileToAll(file);
} catch (IOException e) {
e.printStackTrace();
}
}
//将字符串进行发送
private void sendFileToAll(File file) {
try {
//3.将服务器磁盘中的文件 输入到内存中来
InputStream is=new FileInputStream(file); //多态 子类对象 传给父类类型
BufferedInputStream br=new BufferedInputStream(is); //包装成字节缓存输入流 传送速度快
//4.定义字节输出流 ,用于将内存中的文件 输出到网络上 (将文件发给别的客户)
OutputStream os=socket.getOutputStream();
PrintStream ps = new PrintStream(os); //包装成打印流
//BufferedOutputStream bos=new BufferedOutputStream(os);
int len;
byte[] buffer=new byte[8192];
// for (Socket onLineSocket : Server.onLineSockets) {
// 除了自己的socket,其他socket我都发!!
if(true){
while ((len=br.read(buffer))!=-1) { //通过 缓存字节输入流 接收字节到 buffer中去 并记录数组中的长度len
ps.write(buffer, 0 , len); //将buffer中的字节 通过打印流 发送到网络介质中去
}
}
// }
// br.close();
// ps.close();
socket.shutdownOutput();
System.out.println("发送给所有客户成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
真的不知道怎么解决 。
因为服务器不知道网络介质上的文件 是什么格式的 所以应该怎么接收呢?
运行结果及报错内容
然后现在的问题就是,第二步到第三步,服务器怎么知道网络上的数据是.jpg格式?
我的解答思路和尝试过的方法
是不是要先用正则表达式先截取小数点后面的格式类型,然后作为消息发过先 然后再进行字符串的拼接,再创建服务器的文件对象?
我想要达到的结果
我希望能达到的效果是 :客户端发送文件到服务器,然后服务器能区别文件格式并将他保存到服务器的磁盘下,然后再将磁盘的文件发回给客户端