利用 Socket 套接字进行面向连接通信的编程。客户端读取本地文件并发送;服务器接收文件并保存到本地文件系统中。
使用说明:请将TransferClient, TransferServer, TempFile三个类编译,他们的类包是FileServer.
客户端:
修改TransferClient: serPort, serIP, filePath, blockNum,的值来符合您机器的系统环境;或者用命令行
格式: java FileServer.TransferClient 文件路径+文件名 服务器IP地址 端口 线程数
C:\>java FileServer.TransferClient e:\GREbulletin.pdf 192.168.1.105 2008 5
服务端:
修改TransferServer: serPort, tempFolder的值来符合您机器的系统环境;或者用命令行
格式: java FileServer.TransferServer 端口 文件夹路径
C:\>java FileServer.TransferServer 2008 F:\tempFolder
文件传输服务端---------------------------------------------------------
package FileServer;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
/**
* Description Socket文件传输服务端
* 默认支持多线程传输,未支持断点续传,未支持内网UDF传输
* Creation Date 07-08-2008 9:00
* @author 卢俊宇
* @version 1.0
*/
public class TransferServer {
/**
* @param args[0] 端口默认2008(例: 2008)
* @param args[1] 接收文件存放路径,默认:和FileServer同一目录\ServerReceive
* (例:x:\example\example\)
*/
public static void main(String[] args) {
try {
int serPort = 2008;//服务器默认端口2008
String tempFolder = System.getProperty("user.dir")+"\\ServerReceive";//临时文件夹,用于存放接收文件
ServerSocket ss = null;//设定Socket
if (args.length<1 || null==args) {
ss = new ServerSocket(serPort);
}else {
//检测输入端口是否正确
if (args[0].replaceAll("\\D", "")!="") {
serPort = Integer.parseInt(args[0].replaceAll("\\D", ""));
}else {
System.out.println("输入的端口有错误,使用系统默认端口");
}
ss = new ServerSocket(serPort);
if (args[1].length()>0) {
tempFolder = args[1];
}
}
System.out.println("Welcome to TransferServer");
System.out.println("服务器启动,监听端口" + ss.getLocalPort());
System.out.println("服务器临时文件路径: "+tempFolder);
while (true) {
Socket s = ss.accept();
new Thread(new ServerThread(s,tempFolder)).start();
}
} catch (IOException e) {
e.getMessage();
System.out.println("服务器端口被占用,或其他问题.");
}
}
}
/**
* Description 服务器线程
* @author 卢俊宇
* @param tempFolder 接收文件存放路径,默认:TransferServer.class所在目录\ServerReceive
* (例:x:\example\example\)
* @version 1.1
*/
class ServerThread implements Runnable {
Socket s;// 实例化socket类
private String tempFolder;//临时文件夹名
public ServerThread(Socket s,String tempFolder) {
this.s = s;
this.tempFolder = tempFolder;
}
@SuppressWarnings("deprecation")
public void run() {
try {
InputStream ins = s.getInputStream();
OutputStream outs = s.getOutputStream();
DataInputStream dis = new DataInputStream(ins);
DataOutputStream dos = new DataOutputStream(outs);
// 取得线程ID
String SerID = "SerID-" + Thread.currentThread().getId();
while (true) {
try {
String inStr = dis.readUTF();
// 接收到的文件包含头信息
if (inStr != null) {
// 对收到的socket包过滤出文件信息
if (inStr.contains("ClientInfo")) {
System.out.println(SerID + " get FileInfo! ");
// 文件名字
String fName = new String(inStr.replaceAll(
"(.+<FileName>)|(<\\/FileName>\\S+)", "")
.toString().getBytes("utf-8"), "utf-8");
// 文件总长度
String fSize = new String(inStr.replaceAll(
"(.+<FileLength>)|<\\/FileLength>", "")
.toString().getBytes("utf-8"), "utf-8");
System.out.println("size: " + fSize);
long Size = Long.parseLong(fSize);
// 区块起始长度
String fPs = new String(
inStr
.replaceAll(
"(.+<FilePointerStart>)|(</FilePointerStart>\\S+)",
"").toString().getBytes(
"utf-8"), "utf-8");
System.out.println("PS: " + fPs);
// 区块结束长度
String fPe = new String(
inStr
.replaceAll(
"(.+<FilePointerEnd>)|(</FilePointerEnd>\\S+)",
"").toString().getBytes(
"utf-8"), "utf-8");
System.out.println("PE: " + fPe);
long PointS = Long.parseLong(fPs); // 分块头
long PointE = Long.parseLong(fPe); // 分块尾
System.out.println("SourceFile Name :" + fName);
File tempF = new File(tempFolder, fName);
if (!tempF.exists()) {
//检测目标文件夹是否存在
if (new File(tempFolder).isDirectory()) {
TempFile.creat(tempF, Size);// 如果临时文件不存在就建立
}else {
boolean creat = new File(tempFolder).mkdirs();
if (creat) {
TempFile.creat(tempF, Size);// 如果临时文件不存在就建立
}else {
System.out.println("Error:System can not creat folder!");
System.out.println(SerID+" exits");
dis.close();// 关闭包类
dos.close();// 关闭输出流
s.close();// 关连接
Thread.currentThread().stop();
}
}
}
// 返回服务器准备好了
String SerReady = SerID + " ServerReady=1";
dos.writeUTF(SerReady);// 返回服务器信息
dos.flush();
// 取得客户端发送标志"SendStart"
if (dis.readUTF().equals("SendStart")) {
// 随机读写文件(适应多线程方式)
RandomAccessFile fos = new RandomAccessFile(
tempF.getPath(), "rw");
long curPoint = PointS;// 文件指针起点
long endSet = PointE;// 文件指针终点
long nowSize = 0;// 已读/写字节
byte[] buffer = new byte[1024]; // 建立缓冲区
while (curPoint < endSet) {
int length = 0;
try {
if ((endSet - curPoint + 1) < 1024) {
fos.seek(curPoint);// 寻找写入位置
byte[] bufferM = new byte[(int) (endSet
- curPoint + 1)];// 调整缓冲区大小
length = ins.read(bufferM);// 读取bufferM缓冲socket流
try {
fos.write(bufferM);// 将取得的socket流写入文件
dos.writeUTF("SerGotIt");// 返回服务器信息
dos.flush();
curPoint += length;// 文件指针增加
nowSize += length;
fos.close();
// 向发送接收结束标志
dos.writeUTF("ReciveEnd");
dos.flush();
System.out.println(SerID
+ " is receive ok.");
break;
} catch (IOException e) {
e.printStackTrace();
}
} else {
fos.seek(curPoint);
length = ins.read(buffer);
}
} catch (IOException e) {
e.printStackTrace();
System.out.println(SerID + " is abnormally closed.");
break;
}
if (length == buffer.length) {
// 将缓冲区字节写入文件
try {
System.out
.println(SerID
+ " receive "
+ buffer.length
+ " bytes.");
fos.write(buffer);
dos.writeUTF("SerGotIt");// 返回服务器信息
dos.flush();
curPoint += buffer.length;// 指针+1024
nowSize += buffer.length;
System.out.println(SerID + " 指针位置 "
+ curPoint);
System.out.println(SerID
+ "线程size写入进度:" + nowSize);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
// 接收到客户端结束标志,跳出循环
if (dis.readUTF().equals("SendEnd")) {
System.out.println("服务器接收完毕");
break;
}
} catch (SocketException s) {
// s.printStackTrace();
// 客户端非正常退出处理
System.out.println(SerID + " is abnormally closed.");
break;
}
}
dis.close();// 关闭包类
dos.close();// 关闭输出流
s.close();// 关连接
System.out.println(SerID + " exited.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
文件传输客户端
-----------------------------------------------------------
package FileServer;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Description Socket文件传输客户端(默认支持多线程传输,未支持断点续传,未支持内网UDF传输)
* Creation Date 07-08-2008 9:00
* @author 卢俊宇
* @version 1.0
*/
public class TransferClient {
/**
* Description 文件传输客户端
*
* @param args[0]
* 文件路径+文件名(例:x:\example\example.class)
* @param args[1]
* 服务器IP地址(例: 192.168.1.1)
* @param args[2]
* 端口默认2008(例: 2008)
* @param args[3]
* 区块长度默认5 (例: 5)
*/
public static void main(String[] args) {
int serPort = 2008;// 默认连接端口2008;
int blockNum = 5;// 文件区块数量(同时决定线程数)
String serIP = "192.168.1.105";// 服务器IP
String filePath = "e:\\1.rar";// 欲发送文件路径+文件名
if (args.length<1 || null==args) {
System.out.println("采用默认配置连接");
} else {
if (args[0].length()>0) {
filePath = args[0];
}
if (args[1].length()>0) {
serIP = args[1];
}
if (args[2].length()>0) {
serPort = Integer.parseInt(args[2]);
}
if (args[3].length()>0) {
blockNum = Integer.parseInt(args[3].replaceAll("\\D", ""));
}
}
System.out.println("文件路径: "+filePath);
System.out.println("连接IP: "+serIP);
System.out.println("连接端口: "+serPort);
System.out.println("线程数: "+blockNum);
// 取得文件信息
File source = new File(filePath);
if (!source.exists()) {
System.out.println("要传输的文件不存在!");
System.exit(0);
}
long fSize = source.length(); // 文件长
SimpleDateFormat sdf = new SimpleDateFormat("yyMMddhhmmss");
String currentTime = sdf.format(new Date());
String fName = currentTime + Math.round(100) + "-" + source.getName();// 按时间生成文件名
System.out.println("源文件长度 " + fSize+" bytes.");
// 区块信息
long blockSize = fSize / blockNum; // 区块长度
String[] fInfo = new String[blockNum];// 按区块生产文件信息组
long offset = 0;// 区块起点位置
long endset = 0;// 区块终点位置
String sourceFilePath = source.getPath();// 取源文件路径
// 打包区块信息
for (int i = 0; i < blockNum; i++) {
offset = ((long) i) * blockSize;// 设置文件指针起点
endset = (((long) i + 1) * blockSize - 1 + (i == blockNum - 1
? fSize % blockNum
: 0));// 设置文件指针终点
fInfo[i] = "ClientInfo<FileName>" + fName + "</FileName>";
fInfo[i] += "<FilePointerStart>" + offset + "</FilePointerStart>";
fInfo[i] += "<FilePointerEnd>" + endset + "</FilePointerEnd>";
fInfo[i] += "<FileLength>" + fSize + "</FileLength>";
// 按区块开启线程
new Thread(new FileTransThread(fInfo[i], sourceFilePath, offset, endset,
serIP, serPort)).start();
}
}
}
/**
* Description 文件传输线程
*
* @author 卢俊宇
* @param info;
* 初始化时打包的文件信息
* @param sourceFilePath
* 文件路径+文件名(例:x:\example\example.class)
* @param offSet
* 文件指针起点值地址(按文件区块数量划分)
* @param endSet
* 文件指针终点值地址(按文件区块数量划分)
* @param serPort
* 默认连接端口2008;
* @param serIP
* 连接IP
* @version 1.1
*/
class FileTransThread implements Runnable {
private String info;// 文件信息
private String sourceFilePath;// 源文件路径
private long offSet;// 这个线程写入文件起始值地址
private long endSet;// 这个线程写入的文件长度
private int serPort;// 默认连接端口2008;
private String serIP;// 连接IP
FileTransThread(String info, String sourceFilePath, long offSet, long endSet,
String serIP, int serPort) {
this.info = info;
this.sourceFilePath = sourceFilePath;
this.offSet = offSet;
this.endSet = endSet;
this.serIP = serIP;
this.serPort = serPort;
}
public void run() {
try {
String CliID = "ClientID-" + Thread.currentThread().getId();
System.out.println(CliID + " connect " + serIP);
Socket s = new Socket(InetAddress.getByName(serIP), serPort);
System.out.println(CliID + " successfully connected.");
InputStream clientIn = s.getInputStream();
OutputStream clientOut = s.getOutputStream();
DataInputStream dis = new DataInputStream(clientIn);
DataOutputStream dos = new DataOutputStream(clientOut);
dos.writeUTF(info);// 发送文件信息到服务器
dos.flush();
System.out.println(CliID + " send FileInfo!");
while (true) {
String inStr = dis.readUTF();
// 判断服务器是否准备接收
if (inStr.contains("ServerReady=1")) {
System.out.println(CliID + " report: " + inStr);
// 开始准备文件传输
dos.writeUTF("SendStart");// 发送接收标志
dos.flush();
RandomAccessFile fos = new RandomAccessFile(sourceFilePath,
"r");
long curPoint = offSet;
long nowSize = 0;
byte[] buffer = new byte[1024];
while (curPoint < endSet) { // 建立缓冲区
int length = 0;
try {
if ((endSet - curPoint + 1) < 1024) {
fos.seek(curPoint);
byte[] bufferM = new byte[(int) (endSet
- curPoint + 1)];// 调整缓冲区大小
length = fos.read(bufferM);
try {
clientOut.write(bufferM);
clientOut.flush();
//等待服务器确认
for(;;){
if (dis.readUTF().equals("SerGotIt")) {
break;
}
}
curPoint += length;
nowSize += length;
fos.close();
System.out.println(CliID + " is send ok.");
break;
} catch (IOException e) {
e.printStackTrace();
System.out.println(CliID + " is abnormally closed.");
break;
}
} else {
fos.seek(curPoint);
length = fos.read(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
if (length == buffer.length) {
// 将缓冲区字节写入文件
try {
System.out.println(CliID + " send "
+ buffer.length + " bytes.");
clientOut.write(buffer);
clientOut.flush();
//等待服务器确认
for(;;){
if (dis.readUTF().equals("SerGotIt")) {
break;
}
}
curPoint += buffer.length;// 指针+1024
nowSize += buffer.length;
System.out.println(CliID + " 指针位置 " + curPoint);
System.out.println(CliID + "线程size读入进度:"
+ nowSize);
} catch (IOException e) {
e.printStackTrace();
System.out.println(CliID + " is abnormally closed.");
break;
}
}
}
}
// 向服务端发送结束标志,跳出循环
if (dis.readUTF().equals("ReciveEnd")) {
dos.writeUTF("SendEnd");
dos.flush();
System.out.println("传输完毕");
break;
}
}
dis.close();// 关闭包类
dos.close();// 关闭输出流
s.close();// 关连接
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
生成临时文件
package FileServer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Description 生成临时文件
* Creation Date 07-08-2008 9:00
* @author 卢俊宇
* @version 1.0
*/
public class TempFile {
/**
* 创建文件
* @param targetFile 文件对象
* @param fileLength 文件字节长度
*/
public static void creat(File targetFile, long fileLength) {
long now = System.currentTimeMillis();
long length = fileLength;//指定写入文件文件大小
byte[] buffer = new byte[1024];// 缓冲区1024 bytes
FileOutputStream fos;
try {
fos = new FileOutputStream(targetFile);
while (true) { // 建立缓冲区
if (length > 1024) {
// 将缓冲区字节写入文件
try {
fos.write(buffer);// 写入缓冲
length = length - 1024;
} catch (IOException e) {
e.printStackTrace();
}
} else {
byte[] buf = new byte[(int) length];
System.arraycopy(buffer, 0, buf, 0, (int) length);
try {
fos.write(buf);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
System.out.println("写入临时文件" + targetFile.getName() + ":"
+ targetFile.length() + " bytes");
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("临时文件" + targetFile.getName() + "写入耗时:"
+ (end - now) + " ms");
}
}
-文件传输包含3个类---------------------------------------------------
效果:我已经测试过该程序了,能成功运行!可以多线程
FileServer.rar (5.9 KB)
描述: java源文件
下载链接:
http://dl.iteye.com/topics/download/f28c97a6-91c2-391a-ad95-8fba65a2e088