服务器配置代码:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* extends 表示继承,子类可以继承父类的属性和行为,但是子类不能继承父类的构造器。
* ocketserver是标准库中的一个高级模块
* socketserver可以简化创建客户端跟创建服务端的代码
* SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端
*/
public class Server extends ServerSocket {
static final int SERVER_PORT = 8889;//服务器端口
public Server() throws Exception {
super(SERVER_PORT);
}
/**
*
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
try {
Server server = new Server();//启动服务端
server.load();
System.out.println("-----------服务器启动,等待客户端连接--------");
} catch (Exception e) {
e.printStackTrace();
}
}
//使用线程处理每个客户端的传输文件
public void load() throws Exception {
while (true) {
//server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的
Socket s = this.accept();
//每收到一个socket就建立一个新的线程来处理它
new Thread(new Task(s)).start();
}
}
/*
Runnable只有一个抽象的run()方法,此方法是在运行时由JVM调用,
每一个运行期的Runnable实现类实例(包括Thread的子类,因为Thread亦是实现了Runnable接口)都对应于操作系统中的一个线程,
所以说Java中的线程只是操作系统线程的一个映射,Java中线程的运行效率也不可能高于底层语言线程,
因为Java中线程的创建和调用需要经过JVM,JVM再向下调用(JNI的方式与特定平台进行通信)
处理客户端传输来的文件线程类
*/
static class Task implements Runnable {
private Socket s;
public Task(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
byte[] bys = new byte[1024];
int fileLen = is.read(bys);
String fileName = new String(bys, 0, fileLen);//长度不是bys.length
// System.out.println("文件名是" + fileName);
//查找文件
File file = new File("F:/experiment/ServerFile/" + fileName);
if (file.exists()) {
System.out.println("-------文件存在,开始传输给客户端--------");
//如果有这个文件,服务器将这个文件发送给客户端
dos.writeUTF("right");//信号
//查文件长度,并传输
dos.writeLong(file.length());
dos.flush();
// System.out.println("file.length = " + file.length());
//传输文件
FileInputStream fis = new FileInputStream(file);
int len = fis.read(bys, 0, bys.length);
long progress = 0;
while (progress < file.length()) {
os.write(bys, 0, len);
os.flush();
progress += len;
System.out.println(progress);
System.out.println("文件传输进度为:|" + 100 * (progress / file.length()) + "%|");
}
System.out.println();
System.out.println("---------文件发送成功--------");
fis.close();
} else {
//如果不存在这个文件,服务器发送文件不存在的错误信息到客户端
System.out.println("发送错误信息:文件不存在!");
dos.writeUTF("404NOTFOUND");
dos.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
客户端配置代码:
import java.io.*;
import java.net.Socket;
public class Client extends Socket {
static final String SERVER_IP = "127.0.0.1";
static final int SERVER_PORT = 8889;
Socket s;
//构造函数建立连接
public Client() throws Exception {
super(SERVER_IP, SERVER_PORT);
this.s = this;
System.out.println("Client[port:" + s.getLocalPort() + "]成功连接服务器。");
}
/**
* 主函数
*/
public static void main(String[] args) throws Exception {
try {
Client s = new Client(); //启动客户端连接
s.getFile();
} catch (Exception e) {
e.printStackTrace();
}
}
//接受服务器文件
public void getFile() throws Exception {
OutputStream os = s.getOutputStream();
InputStream is = s.getInputStream();
DataInputStream dis = new DataInputStream(is);
try {
//查询文件
os.write("test.txt".getBytes());
os.flush();
System.out.println("客户端已发送要查询的文件名。");
String sign = dis.readUTF();
if ("404NOTFOUND".equals(sign)) {
System.out.println("收到错误信息:文件不存在!");
return;
}
if ("right".equals(sign)) {
System.out.println("-------开始接收--------");
//接收文件长度
long fLen = dis.readLong();
System.out.println("fLen为" + fLen);
//接受文件
File file = new File("F:/experiment/ClientFile/test.txt");//创建文件
System.out.println("file.length" + file.length());
FileOutputStream fos = new FileOutputStream(file, true);
byte[] bys = new byte[1024];
int len = is.read(bys, 0, bys.length);
System.out.println("file.length" + file.length());
while (fLen > file.length()) {
fos.write(bys, 0, len);
fos.flush();
System.out.println("file的长度为:" + file.length());
}
System.out.println("-------文件接收完成-------");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
is.close();
os.close();
}
}
}