java socket传多个文件的疑问?望解答

zg6002 asdf  2010-07-02 02:42:34
服务端:ServerSocket server = new ServerSocket(9527);

客房端:Socket socket = new Socket(IP,9527);

问题:传输一个,十个,百个文件都没事,可是现在要传一个文件夹里面有上百万个文件,每次传完一个文件就要重新执行
new Socket(IP,9527);一变,次数多了会有一异常出现,

现在想有没有办法只实现一次new Socket(IP,9527);(把客户端与服务端连接建立后)就利用这一个连接传多个文件?不在for循环里写连接代码?
...全文
486 点赞 收藏 21
写回复
21 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
_真真 2012-07-30
非常感谢16楼的亲情奉献,, 我研究了好久都没弄出来.
回复
阿贝啊啊 2012-04-30
多谢上面的回答。
回复
tanrenzong1986 2011-07-21
传输这么多文件,为什么不用FTP啊。
回复
dog12ccc 2011-07-21
我们的教科书上面也弄错了 客户端是用输出流吧? 服务器是输入流 吧? 是不是哦? 忘记了
回复
guoao_xxL 2011-07-21
楼上写的 正好需要了!
感谢
回复
kala197 2010-07-05
嘿嘿ie 顶个 虽然搞Java 但是还没用的过socket
回复
「已注销」 2010-07-05

发送方
dos.writeInt(files.size());//文件个数
for(File f:files){
dos.writeUTF(f.getName());//文件名
dos.writeLong(f.length());//文件长度
dos.write(...);//文件内容
}

接收方
int n = dis.readInt();//文件个数
for(int i=0;i<n;i++){
String filename = dis.readUTF();//文件名
long length = dis.readLong();//文件长度
dis.read(...);//读取length长度的字节
...//保存文件
}
回复
zg6002 2010-07-05
发送端用 out.writeUTF("end");表示一份文件完成,开发送下一份文件
接收端:
while((ch = in.read(buf))!=-1) {
len += ch;
DiaInfo.pb1.setValue(len);
DiaInfo.pb1.setString(len+"/"+size);
fos.write(buf,0,ch);
fos.flush();
if("end".equals( in.readUTF())) {
System.out.println("关闭");
break;
}
}
这样写不行了,只要运行到"end".equals( in.readUTF())这句就报错malformed input around byte
应该怎么做标记?
回复
xtuxucj 2010-07-05
在来一个BteBuffer的,但没实现NIO这个功能。NIO不太会,呵呵。代码没注释,写的很粗糙。就写了基本功能。
客户端

package nioserver;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

public class ChannelClient {
private SocketChannel sc;
private String hostIp;
private int hostPort;

public ChannelClient(String hostIp, int port) {
this.hostIp = hostIp;
this.hostPort = port;
}

private void setUpConnection() {
try {
SocketAddress remote = new InetSocketAddress(hostIp, hostPort);
sc = SocketChannel.open();
sc.connect(remote);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private void sendFiles(File[] files) {
FileChannel fileChannel = null;
try {
for (int i = 0;i < files.length; i++) {
byte[] namebyte = files[i].getName().getBytes("UTF-8");
long size = files[i].length();
int nameLength = namebyte.length;
fileChannel = new FileInputStream(files[i]).getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.clear();
buffer.putInt(4+8+nameLength);
buffer.putInt(nameLength);
buffer.put(namebyte);
buffer.putLong(size);
buffer.flip();
while(buffer.hasRemaining()){
sc.write(buffer);
}
long count = 1024*1024;
long read = 0L;
while(read < size){
if(size - read < count)
count = size - read;
read += fileChannel.transferTo(0+read, count, sc);
System.out.println("read:"+read);
}
fileChannel.close();
if(i < files.length -1){
sc.write(ByteBuffer.wrap(new byte[]{1}));
System.out.println(1);
}
else
sc.write(ByteBuffer.wrap(new byte[]{0}));
}

sc.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
ChannelClient client = new ChannelClient("127.0.0.1", 3000);
client.setUpConnection();
File[] files = new File("D:\\send").listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.isFile();
}
});
client.sendFiles(files);
}

}


服务器端

package nioserver;

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class FilesChannelServer {
private String fileName = null;
private long fileSize = 0L;
private int hostPort;
private ServerSocketChannel ssl = null;
private SocketChannel clientChannel = null;
private ByteBuffer buffer = null;

public FilesChannelServer(int port) {
this.hostPort = port;
}

private void setUpConnection() {
try {
ssl = ServerSocketChannel.open();
SocketAddress address = new InetSocketAddress("127.0.0.1", hostPort);
ssl.socket().bind(address);
System.out.println("bind.....");
} catch (IOException e) {
e.printStackTrace();
}
}

private void parseHead(int headlength) {
buffer = ByteBuffer.allocate(headlength);
try {
while(buffer.position() < buffer.capacity())
clientChannel.read(buffer);
buffer.flip();
byte[] filenamebyte = new byte[buffer.getInt()];
buffer.get(filenamebyte);
fileName = new String(filenamebyte,"UTF-8");
fileSize = buffer.getLong();
} catch (IOException e) {
e.printStackTrace();
}
}

private void parseBody(long size) {
long read = 0L;
long count = 8192;
FileChannel fileChannel = null;
try {
fileChannel = new FileOutputStream("D:\\receive\\" + fileName)
.getChannel();
System.out.println(fileName);
while (read < size) {
if (size - read < count)
count = size - read;
read += fileChannel
.transferFrom(clientChannel, 0 + read, count);
}

} catch (IOException e) {
e.printStackTrace();
}finally{
try {
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

private int parse() {
int i = 0;
try {
buffer = ByteBuffer.allocate(4);
while(buffer.position() < buffer.capacity())
clientChannel.read(buffer);
buffer.flip();
parseHead(buffer.getInt());
parseBody(fileSize);
buffer = ByteBuffer.allocate(1);
while(buffer.position() < buffer.capacity())
clientChannel.read(buffer);
buffer.flip();
i = buffer.get();
} catch (IOException e) {
e.printStackTrace();
}

return i;
}

private void acceptConnection() {
while (true) {
try {
clientChannel = ssl.accept();
int j = 1;
while(j != 0){
j = parse();
System.out.println(j);
}
} catch (IOException e) {
e.printStackTrace();
} finally {

try {
if (clientChannel != null)
clientChannel.close();
} catch (IOException e) {
e.printStackTrace();
}

}

}
}

public static void main(String[] args) {
FilesChannelServer cs = new FilesChannelServer(3000);
cs.setUpConnection();
cs.acceptConnection();
}
}

这里说明下。可以说是我自定义的协议吧。
一共分成6段
在bytebuffer中第一个4个byte,存放第二段到地四段的byte长度
第二段,四个byte长度是文件名转换成byte数组的长度(file.getName().getBytes("UTF-8").length)
第三段,存放文件名转换的byte(file.getName().getBytes("UTF-8"))
第四段,8个bte存放文件的大小(file.getSize())
第五段,存放文件的byte形式,
第六段,1个byte长度,如果还有后续的文件存放1,如果文件传送完了就存放0
回复
ChDw 2010-07-05
只要双方都关闭了Socket,那么不应该出现问题的
回复
xtuxucj 2010-07-05
实在不行就搞个ZipInoutStream。按顺序把文件写到ZipInoutStream中,在另一端解压缩就行。或者自己定义一个解析规定。
贴上我的代码。这个还没整理过。作用是从客服端往服务器端发送文件。
客服端代码

package net;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
* @author Life
*发送文件的客户端
*/
public class FileSendClient {
protected String hostIP;
protected int hostPort;
protected OutputStream socketInS;
private Socket client;

public FileSendClient(String ip, int portNumber) {
this.hostIP = ip;
this.hostPort = portNumber;
}

/**
* 建立连接
*/
public void setUpConnection() {
try {
client = new Socket(hostIP, hostPort);
socketInS = client.getOutputStream();
} catch (UnknownHostException e) {
throw new RuntimeException(e.toString());
} catch (IOException e) {
throw new RuntimeException(e.toString());
}

}

/**
* @param files
* 用zip流发送多个文件
*
*/
public void sendFile(File[] files) {
BufferedInputStream fileReader = null;
ZipOutputStream zos = new ZipOutputStream(socketInS);
BufferedOutputStream socketWriter = new BufferedOutputStream(zos);
byte[] buff = new byte[8192];
int c = 0;
try {
for (File file : files) {
fileReader = new BufferedInputStream(new FileInputStream(file));
zos.putNextEntry(new ZipEntry(file.getName()));
while ((c = fileReader.read(buff)) != -1) {
socketWriter.write(buff, 0, c);
}
socketWriter.flush();
try {
if (fileReader != null)
fileReader.close();
} catch (IOException e) {
System.out.println("Error closing fileReader" + e);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socketWriter != null )
socketWriter.close();
} catch (IOException e) {
System.out.println("Error closing socketWriter" + e);
}finally{
if(client != null && client.isConnected()){
try {
client.close();
} catch (IOException e) {
System.out.println("Error closing socket" + e);
}
}
}

}

}

public static void main(String[] args) {
FileSendClient fileSendClient = new FileSendClient("127.0.0.1", 3000);
fileSendClient.setUpConnection();
File[] files = new File("D:\\send").listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.isFile();
}
});
fileSendClient.sendFile(files);

}
}

服务器端代码:

package net;

import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;


/**
* @author Life
*文件接收服务器
*/
public class FileReceiveServer {
protected int listenPort;
private int maxConnection;

public FileReceiveServer(int listenPort,int maxConnection) {
this.listenPort = listenPort;
this.maxConnection = maxConnection;
}

/**
* 建立监听端口
*/
public void setUpConnection(){
for(int i = 0; i < maxConnection; i++){
new Thread(new FileReceiverHandle(),"handle"+i).start();
}


}

/**
* 接收文件客户端的连接
*/
public void acceptConnection() {
try {
ServerSocket server = new ServerSocket(listenPort);
Socket incomingSocket = null;
while (true) {
incomingSocket = server.accept();
handlerConnection(incomingSocket);
}
} catch (BindException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}

/**
* @param incomingSocket
* 处理接收到的连接(socket)
*/
private void handlerConnection(Socket incomingSocket) {
FileReceiverHandle.processConnection(incomingSocket);

}

public static void main(String[] args) {
FileReceiveServer fileReceiveServer = new FileReceiveServer(3000,5);
fileReceiveServer.setUpConnection();
fileReceiveServer.acceptConnection();
}

}



package net;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
* @author Life
*文件接收处理程序
*/
public class FileReceiverHandle implements Runnable {
private static List<Socket> socketsPool = new LinkedList<Socket>();
private Socket connection = null;

/**
* @param incomingSocket
* 降接收到的连接放到一个池中
*
*/
public static void processConnection(Socket incomingSocket) {
synchronized (socketsPool) {
socketsPool.add(socketsPool.size(), incomingSocket);
socketsPool.notifyAll();
}
}

/**
* 按zip流解码获取接收到的流
*/
public void handlerConnection() {
InputStream inputFromSocket = null;
BufferedOutputStream fileWriter = null;
BufferedInputStream socketReader = null;
byte[] buff = new byte[8192];
int c = 0;
try {
inputFromSocket = connection.getInputStream();
ZipInputStream zis = new ZipInputStream(inputFromSocket);
socketReader = new BufferedInputStream(zis);
ZipEntry e = null;
while ((e = zis.getNextEntry()) != null) {
System.out.println(e.getName());
fileWriter = new BufferedOutputStream(new FileOutputStream(
new File("D:\\receive\\" + e.getName())));
while ((c = socketReader.read(buff)) != -1) {
fileWriter.write(buff, 0, c);
}
try {
fileWriter.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socketReader != null) {
socketReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try{
if(connection != null){
connection.close();
}
}catch(IOException e){
e.printStackTrace();
}
}

}
}

/*
* 处理池中的连接
*/
public void run() {
while (true) {
synchronized (socketsPool) {
while (socketsPool.isEmpty()) {
try {
socketsPool.wait();
} catch (InterruptedException e) {
return;
}
}
connection = socketsPool.remove(socketsPool.size() - 1);
}
handlerConnection();
}
}

}
回复
guobaoaskformore 2010-07-02
自己设置一个文件分隔标识吧,搞复杂一些,当发送一个文件结束后,将该分隔标识发出去,客户端读到这一行就表示一个文件结束,则开始读取下个文件
如果觉得土,可以看看,一些FTP的源码如何处理的。
回复
zg6002 2010-07-02
现在的问题就是怎么判断什么时候发送完一个文件,什么时候开始接收下一个文件
回复
zuoguodang 2010-07-02
连一次啊,发文件就是遍历文件一个一个的发
回复
俊哥123 2010-07-02
无论是发送还是接受方都不要重复的new socket,
第一次使用时判断是否为空,为空才new,所有的任务做完了,才能关闭。
你把握这一点,程序就OK了

用while(true){
Thread.sleep(1000l);
if(inputStream.available()>0){
//判断有数据过来,接收

}
}
回复
zg6002 2010-07-02
发送方:int t = 0;
while((ch = fis.read(buf))!=-1) {
t += ch;
out.write(buf,0,ch);
if(t == (int)f.length()) {
break;
}
}


接收方:while((ch = in.read(buf))!=-1) {
len += ch;
DiaInfo.pb1.setValue(len);
DiaInfo.pb1.setString(len+"/"+size);
fos.write(buf, 0, ch);
if(len == size) {
break;
}
}
回复
zg6002 2010-07-02
发送端和接收端都有一个while循环 通过in.read(buf))!=-1退出
如果不重新连一下服务,用一个连接的话,发送端和接收端怎么判断什么时候接收新的文件?
回复
prince_java 2010-07-02
你不会把Socket写在for循环里了吧- -!
客户端就写一个Socket连接,用BufferedReader从键盘接收你要传的文件或文件夹,然后用if进行判断,如果你要传的类型是文件,那好,直接用输入输出流进行复制,如果是文件夹,那就用for循环对文件夹进行遍历,是文件就复制文件,是文件夹的就按照文件夹的名字新建文件夹
回复
俊哥123 2010-07-02
你这样老new socket,再牛逼的电脑,连接缓存都要搞没了
你在外面定义好一个socket,和输入输出流
new 一次,以后重用
所有文件发完了再关闭。
回复
magicbu 2010-07-02
为什么要重新执行new Socket(IP,9527)
好像没必要吧~
回复
加载更多回复
相关推荐
发帖
Java SE
创建于2007-09-28

6.2w+

社区成员

Java 2 Standard Edition
申请成为版主
帖子事件
创建了帖子
2010-07-02 02:42
社区公告
暂无公告