赞
踩
一。socket文件传输
1。局域网文件传输和复制,含文件名(本节转自WW。CSDN。NET文章:(因为了分析比较))
实施局域网内文件复制,包括需要把文件名也拷贝过去。特点是文件名传输和文件传输动用了两个端口。进程完成这样的功能:每隔24小时进
行上传一次,保持两台机器的根目录下文件一致。
服务器端,也既待上传端。运行命令:java FileServer 3107
import java.io.*;
import java.net.*;
public class FileServer implements Runnable {
private static int ipsocket = 0;
public static void main(String[] args)throws Exception{
ipsocket = Integer.parseInt(args[0]);
//建议使用3107
System.out.println("系统在端口:" + ipsocket + "等待发送");
Thread t1 = new Thread(new FileServer());
t1.start();
}
public void run(){
while(true){
try{
String[] fileNames = seachFileName(1);
if(fileNames == null || fileNames.length < 1) return;
for(int i = 0; i < fileNames.length; i ++){
sendFileName(fileNames[i]);
sendFile(fileNames[i]);
}
Thread.sleep(24 * 60 * 60 * 1000); //24小时
}catch(Exception e) {
System.out.println(e);
}
}
}
/*
listType = 0 返回含文件夹和文件
listType = 1 只返回文件
*/
public static String[] seachFileName(int listType) throws Exception{
String directory = ".";
File dir = new File(directory);
File dirTemp;
String[] filesTemp;
String[] fileNames;
String[] re;
int length = 0;
if (!dir.isDirectory())
throw new IllegalArgumentException("FileList: no such directory");
filesTemp = dir.list();
java.util.Arrays.sort(filesTemp);
for(int i = 0; i < filesTemp.length; i++) {
dirTemp = new File(directory + "//" + filesTemp[i]);
if(!dirTemp.isDirectory()){
length++;
}
}
fileNames = new String[length];
length = 0;
for(int i = 0; i < filesTemp.length; i++) {
dirTemp = new File(directory + "//" + filesTemp[i]);
if(!dirTemp.isDirectory()){
fileNames[length] = filesTemp[i];
}
length++;//************这里我认为是应该放进if(){}中。***************
}
if(listType == 0) re = filesTemp;
else re = fileNames;
return re;
}
/*发文件名
*/
private static void sendFileName(String fileNames) throws Exception{
if(fileNames == null) return;
//创建网络服务器接受客户请求
ServerSocket ss=new ServerSocket(ipsocket);
Socket client=ss.accept();
//创建网络输出流并提供数据包装器
OutputStream netOut=client.getOutputStream();
OutputStream doc=new DataOutputStream(new BufferedOutputStream(netOut));
//创建文件读取缓冲区
byte[] buf=null;
String fileName = fileNames;
buf = fileName.getBytes();
int num=buf.length;
if(num > 0){//是否读完文件
doc.write(buf,0,num);//把文件数据写出网络缓冲区
doc.flush();//刷新缓冲区把数据写往客户端
}
doc.close();
ss.close();
}
/*发文件本身
*/
private static void sendFile(String fileName) throws Exception{
if(fileName == null) return;
//创建文件流用来读取文件中的数据
File file=new File(fileName);
FileInputStream fos=new FileInputStream(file);
//创建网络服务器接受客户请求
ServerSocket ss=new ServerSocket(ipsocket + 1);
Socket client=ss.accept();
//创建网络输出流并提供数据包装器
OutputStream netOut=client.getOutputStream();
OutputStream doc=new DataOutputStream(new BufferedOutputStream(netOut));
//创建文件读取缓冲区
byte[] buf=new byte[2048];
int num=fos.read(buf);
while(num!=(-1)){//是否读完文件
doc.write(buf,0,num);//把文件数据写出网络缓冲区
doc.flush();//刷新缓冲区把数据写往客户端
num=fos.read(buf);//继续从文件中读取数据
}
fos.close();
doc.close();
ss.close();
}
}
2:客户端,也既文件接受端。运行命令:java FileClient 127.0.0.1 3107。注意跟服务器端口要一致。
import java.io.*;
import java.net.*;
public class FileClient implements Runnable {
private static String ip = "";
private static int ipsocket = 0;
public static void main(String[] args)throws Exception{
ip = args[0];
ipsocket = Integer.parseInt(args[1]);
//建议使用3107
System.out.println("系统在地址@" + ip + ":" + ipsocket + "倾听");
Thread t1 = new Thread(new FileClient());
t1.start();
}
public void run(){
while(true){
try{
String strTemp = getFileName();
getFile(strTemp);
}catch(Exception e){}
try{
Thread.sleep(5 * 1000); //5秒 //****就是每隔5S轮询一次是否有文件要上传咯,这里有二个作用:1。作为服务器某一时间段里围轮询 2。作为经24H后的一次轮询*********过
}catch(Exception e) {
System.out.println(e);
}
}
}
private static String getFileName() throws Exception{
// 通过Socket连接文件服务器
Socket server=new Socket(ip,ipsocket);
//创建网络接受流接受服务器文件数据
InputStream netIn=server.getInputStream();
InputStream in=new DataInputStream(new BufferedInputStream(netIn));
//创建缓冲区缓冲网络数据
byte[] buf=new byte[2048];
int num=in.read(buf);
while(num!=(-1)){//是否读完所有数据 /********这里觉得不是很恰当,可以不用WHILE来读一个文件名吧,本身服务器也是发了一次数据,而且你这样不是每次都覆盖了上次的内容吗?开始看时我也觉得好像自己被蒙蔽了。。。******************
num=in.read(buf);//继续从网络中读取文件
}
String fileName = new String(buf);
fileName = fileName.trim();
in.close();
server.close();
return fileName;
}
private static void getFile(String strTemp) throws Exception{
//使用本地文件系统接受网络数据并存为新文件
File file=new File(strTemp);
//如果文件已经存在,先删除
if(file.exists()) file.delete();
for(int i = 0 ; i < 10000; i++) {}
file.createNewFile();
RandomAccessFile raf=new RandomAccessFile(file,"rw");
// 通过Socket连接文件服务器
Socket server=new Socket(ip,(ipsocket + 1) );
//创建网络接受流接受服务器文件数据
InputStream netIn=server.getInputStream();
InputStream in=new DataInputStream(new BufferedInputStream(netIn));
//创建缓冲区缓冲网络数据
byte[] buf=new byte[2048];
int num=in.read(buf);
while(num!=(-1)){//是否读完所有数据
raf.write(buf,0,num);//将数据写往文件
raf.skipBytes(num);//顺序写文件字节//***********这里应该是错的,raf本身可以自动移动指针,为什么要SKIP?***********
num=in.read(buf);//继续从网络中读取文件
}
in.close();
raf.close();
server.close();
}
}
注:带///********xxxxxxxxxxxxxxxx*******是本人注释。
评论:该文使用了两个端口来实现文件名与文件的传送,方法不错,我以前用DatagramSocket作的文件传输是用一个port的,当然这样要先送一些约定信息,详细见下文。
2。自创。在网上找了很久也没相关的datagramsocket传输文件的文章,有的多是普通传输普通信息,于是我就自己做了一个传输文件的,当然这个例子中有些BUG,有等重构
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.SocketException;
import java.net.InetAddress;
import java.io.File;
import java.io.*;
import java.util.HashMap;
import java.util.Collection;
import java.util.Arrays;
//为了简化,假定这个文件为2-9K之间,如果大于此可能会有异常,但可以修改代码改善
public class Server {
private static DatagramSocket socket ;
private static byte[] buff = new byte[1024];
private static int packetNum;
private static int packetTotal;
private static final int INPORT = 1700;
private static HashMap packets = new HashMap();//use for repackage.
private static Integer packetOrder;
private static RandomAccessFile bufferFile;
private static File resultFile;
private static InetAddress add;
private static DatagramPacket recePacket;
private static DatagramPacket sendPacket;
public static final String path = "d://server//dest";
private static File tempFile;
private static File tempDir;
private static long startApp;
private static long interval = 5000;//by default
private static int resendTime = 0 ;
private static boolean starting = true;
public Server(){
tempDir = new File("d://server//temp");
}
//create a new file only**
public void createFile(String fileName){
if(fileName == null){
System.out.println("Error: the file name send by client is unvalidity!");
return ;
}
resultFile = new File(path,fileName);
try{
//if the file has existed,delete it first
if(!resultFile.createNewFile()){
resultFile.delete();//delete the original file.
}
resultFile.createNewFile();
System.out.println("now a new file send by client is being created on the D://server//dest//"+resultFile.getName()+"...");
}
catch(IOException ioe){
System.out.println("Oops!receive file failed.");
}
}
//为了简化,假定只有一个包未如期接收
private static int checkPacket(){
Collection coll = packets.values();
File[] result = (File[])coll.toArray(new File[0]);
Arrays.sort(result);
for(int i=101;i<=packetTotal;i++){
String index = result[i].getName();
index = index.substring(0,3);
int whichOne = Integer.parseInt(index);
if(i != whichOne)
return i; //MUST be i instead of index!
}
//0 will be return if normall send(but here will not,here is as a request of method)
return 0;
}
public static void main(String[] args) {
// TODO Auto-generated method stu
System.out.println("server has started");
Server server = new Server();
//initialize the scheme.
try{
server.socket = new DatagramSocket(INPORT);
}
catch(SocketException se){
se.printStackTrace();
}
server.recePacket = new DatagramPacket(server.buff,server.buff.length);
//now receive the indentify infomation(file name,the amount of packet...etc)
//filename contains bytes and the amout of the file is denoted by client.
//***the file and packet VIP preformatted information.
//------------new file data format.
//buff[0]= 'n' means a new file else means file's data; ****
//buff[1] = filename lenght;starts buff[2] (if any) is the filename data.
//buff[100] = number of the packet;
//------------packet data format.
//buff[0] means the packet index or the 'r'(error) or 'o'(over) flag .
int index = 100;
//here use a label(like the goto statement in C)***********
String fname = null;
resend:
while(true){
try{
server.socket.receive(server.recePacket);
if(starting){
startApp = System.currentTimeMillis();
System.out.println(startApp);
starting = false;//only use one time
}
byte[] data = new byte[1024];
data = server.recePacket.getData();
//为了简化,默认为当发送过来的第一个字节为‘n'时,就是一个新文件。
//(对应client端,当Server发送一个'r'时,要求重发送指定包。
if(data[0] == 'n'){
fname = new String(data,2,buff[1]);
server.createFile(fname);
packetTotal = data[100];//假定文件个数为(基数100+实际文件数目)
System.out.println("packet total: "+packetTotal);
}
else{
//默认从101开始编号临时文件
index++;//count for the amout of the packets.
//只要有发送过来都是默认为正常要接收的个包
//以下是作为一个文件的建立,关闭操作。
tempFile = new File(tempDir,index+".tmp");
tempFile.createNewFile();
packetOrder = new Integer(index);
packets.put(packetOrder,tempFile);
bufferFile = new RandomAccessFile(tempFile,"rw");
bufferFile.write(data);
bufferFile.close();
//为了简化,只要发送次数等于包数就默认为完毕(可以正常组装)
if(index == packetTotal){
Collection values = packets.values();
//int cnt = values.size();
File[] valInt = (File[])(values.toArray(new File[0]));
Arrays.sort(valInt);
bufferFile = new RandomAccessFile(resultFile,"rw");
for(int i=0;i<valInt.length;i++){
tempFile = valInt[i];
RandomAccessFile transFile = new RandomAccessFile(tempFile,"rw");
buff = new byte[1024];//clear data privor to save
transFile.read(buff);
bufferFile.write(buff);
//需要删除刚才建立的临时文件
if(tempFile.delete()){
System.out.println("temperory file: "+tempFile+" has deleted!");
System.out.println(tempFile.isFile());
}
else
System.out.println("can not delete temperory file: "+tempFile);
transFile.close();
}
packets.clear();
bufferFile.close();
System.out.println("d://server//dest//"+fname+" file successfully received!");
//回传一个'o'(over)标志完毕
server.resend((byte)'o');
break;
}
//假定5s里可以将文件传送完毕;
//如果5s内未完全传送完毕,则要求每隔2s发送一个重发包命令,连续五次,
//如果包还是未到达,那么接收文件失败并删除它
else{
long period = System.currentTimeMillis() - startApp;
System.out.println(period);
if( period > interval ){
System.out.println("resend time");
if(resendTime < 5 ){
resendTime++;
startApp = System.currentTimeMillis();
interval = 2000;//convert to use resend
byte miss = (byte)checkPacket();
//回传要重发的包(注意0值不可能到达,因为上面if(index == packetTotal)会优先检查
//所以这时没有必要做0的情况
if(miss != 0){
server.resend(miss);
System.out.println("miss a package: waiting for it resended by client...");
continue resend;//retry
}
}
else{
System.out.println("Oops!receive file failed.");
server.resend((byte)'r');//r means error
break;
}
}
}
}
}
catch(SocketException se){
System.out.println("connection counld not be opened!");
se.printStackTrace();
System.exit(1);
}
catch(IOException ioe){
System.out.println("the client send a file but you can't receive by any problems.");
ioe.printStackTrace();
System.exit(1);
}
}
}
public void resend(byte flag){
byte[] buf = new byte[10];//reset the data,because the client use only the first byte to resolve so 10B is enough
buf[0] = flag;
sendPacket = new DatagramPacket(buf,buf.length,recePacket.getAddress(),recePacket.getPort());
try{
socket.send(sendPacket);
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
}
import java.net.*;
import java.io.*;
public class Client {
private static DatagramSocket socket ;
private static DatagramPacket recePacket;
private static DatagramPacket sendPacket;
private static final int INPORT = 2100;//==how it do if this is the same as the Server's ?
private static RandomAccessFile raf;
private static InetAddress add ;
private static byte[] buff = new byte[1024];
private static int packetTotal;
private static File tempDir;
private static boolean canSend = true;
private static int baseNum = 100;
private static final String tempFileExtend = ".tmp";
//data format:---------------------------------
/the first transform
//data[100] the amount of the files will be sent
/the later transform
//data[0] = 'n':a new file will be sent;then data[1] = length of filename(in bytes)
// 'r':a error and terminated this transform;
// 'o':exit normally;
// 101 to 109 the resend number.
public Client(){
recePacket = new DatagramPacket(new byte[1024],1024);
try{
add = InetAddress.getByName("59.42.110.15");//==this will be changed if in intranet****
tempDir = new File("d://client//temp");
}
catch(UnknownHostException uhe){
uhe.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Client c = new Client();
try{
socket = new DatagramSocket(INPORT);//2100 is the port of local host
}
catch(SocketException se){
System.out.println("Can't open the connection!");
se.printStackTrace();
}
//the file's length
long bytes = 0;
try{
raf = new RandomAccessFile("d://client//dest//data.txt","rw");
bytes = raf.length();
packetTotal = (int)bytes / 1024;
if(bytes % 1024 != 0)
packetTotal++;//if file's length isn't interger multiple,increase 1
//now it is the real value use for transforming and creating temperory files
packetTotal += baseNum;
//create the tempfile of these packets use for sending or resending and write to a temp file
for(int i= baseNum+1;i<=packetTotal;i++){
File tempFile = new File(tempDir,i+tempFileExtend);
tempFile.createNewFile();
//==tempFile.deleteOnExit();
byte[] buff = new byte[1024];
raf.read(buff);
RandomAccessFile stream = new RandomAccessFile(tempFile,"rw");
stream.write(buff);
}
}
catch(FileNotFoundException fnfe){
fnfe.printStackTrace();
}
catch(IOException ioe){
ioe.printStackTrace();
}
//now start send files or receive any info
try{
buff[0] = 'n';
String sendFile = "data.txt";
int fileNameLength = sendFile.length();
buff[1] = (byte)fileNameLength;
buff[100] = (byte)packetTotal;
//Oops!this is a deprecated method!***********
sendFile.getBytes(0,buff[1],buff,2);
sendPacket = new DatagramPacket(buff,buff.length,add,1700);
socket.send(sendPacket);
int count = 101;
//first,send the indentify data
//this method must NOT block becasue it has additional IP of remote machine
while(true){
if(count <=packetTotal){
setFileData(count);
count++;
}
//this means count is > packetTotal(that is sending is over),now listening any info from Server
//open receive port
else {
System.out.println("receiving....");
socket.receive(recePacket);
byte[] data = recePacket.getData();
if(data[0] == 'o'){
System.out.println("OK!the file has been sent to the Server successfully.");
break;
}
else if(data[0] == 'r'){
System.out.println("Sorry!there are any problems so the file can't been sent.");
break;
}
else {
//read the resend index of the packet
byte resendNO = data[0];
System.out.println("resend package: "+resendNO);
setFileData(resendNO);
count = 101;//reset
}
}
}
}
catch(IOException ioe){
ioe.printStackTrace();
}
finally{
socket.close();
try{
raf.close();
}
catch(IOException ioe){
}
}
}
public static void setFileData(int tempFileNO){
try{
File tempFile = new File(tempDir,tempFileNO+tempFileExtend);
tempFile.createNewFile();
byte[] buff = new byte[1024];
raf = new RandomAccessFile(tempFile,"rw");
raf.read(buff);
sendPacket.setData(buff);
socket.send(sendPacket);
}
catch(FileNotFoundException fnfe){
fnfe.printStackTrace();
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
}
评论:本文采取的分包技术,觉得不是很好,就是将一个文件拆分成几个文件,然后逐个送发;客户端就始终接到送过来的包,如果已经是正常接收完毕,就开始重新组装包;如果是有漏包,就根据包号发送服务器要求重发,服务器则将包号对应 的文件回发,一切完毕后就可以删除所有服务器/客户端的文件了(但这里不知道怎么的老是删除不成功,你知道吗?怎么不告诉我一声哦??),当然例子中涉及受限条件,如果是真正应用的话还是需要调整代码的,因条件而异咯:)
3.自创文章
import java.net.*;
import java.io.*;
public class SocketServer{
public static void main(String[] args) throws Exception{
ServerSocket server = new ServerSocket(3107);
Socket client = server.accept();
OutputStream dos = client.getOutputStream();
for(int i=0;i<10;i++){//会先主动断开
dos.write((byte)i);
dos.flush();
/*try{
Thread.sleep(500);
}
catch(Exception e){
}*/
}
dos.close();
client.close();
server.close();
}
}
import java.net.*;
import java.io.*;
class SocketClient {
public static void main(String[] args) throws Exception{
Socket server = new Socket("127.0.0.1",3107);
InputStream dis = server.getInputStream();
int val = 0;
while((val=dis.read()) != -1){
System.out.println(val);
try{
Thread.sleep(500);
}
catch(Exception e){
}
}
dis.close();
server.close();
}
}
这例子说明,socket其实是"不负责的",它一旦建立连接,只是将自己的任务发出去就算了,我认为流信息始终是先发到端口(它是内存一部分吧),然后客户就读取,其实我觉得这也是客户端能即时读取的原因(我在内部网测试过了,确定是当服务器发送完数据并自动断开连接后,客户端依然可以读取数据),错了吗?好,评论一下吧,我也是刚好的哦!),但客户端却始终准确地读取的,不像DATAGRAM一样检测.
总结:socket是可靠传送信息的方法,但其实是有代码的,包括建立连接,数据校验等;datagram是比较轻型的,它好像是一个智能的子弹,自动跟踪目标;比如就是:SOCKET是打电话,DATAGRAM是信件,不保证你的情信会飞到对方...:)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。