Java Socket实战之七 使用Socket通信传输文件
前面几篇文章介绍了使用Java的Socket编程和NIO包在Socket中的应用,这篇文章说说怎样利用Socket编程来实现简单的文件传输。
这里由于前面一片文章介绍了NIO在Socket中的应用,所以这里在读写文件的时候也继续使用NIO包,所以代码看起来会比直接使用流的方式稍微复杂一点点。
下面的示例演示了客户端向服务器端发送一个文件,服务器作为响应给客户端会发一个文件。这里准备两个文件E:/test/server_send.log和E:/test/client.send.log文件,在测试完毕后在客户端和服务器相同目录下会多出两个文件E:/test/server_receive.log和E:/test/client.receive.log文件。
下面首先来看看Server类,主要关注其中的sendFile和receiveFile方法。
- packagecom.googlecode.garbagecan.test.socket.nio;
- importjava.io.File;
- importjava.io.FileInputStream;
- importjava.io.FileOutputStream;
- importjava.io.IOException;
- importjava.net.InetSocketAddress;
- importjava.nio.ByteBuffer;
- importjava.nio.channels.ClosedChannelException;
- importjava.nio.channels.FileChannel;
- importjava.nio.channels.SelectionKey;
- importjava.nio.channels.Selector;
- importjava.nio.channels.ServerSocketChannel;
- importjava.nio.channels.SocketChannel;
- importjava.util.Iterator;
- importjava.util.logging.Level;
- importjava.util.logging.Logger;
- publicclassMyServer4{
- privatefinalstaticLoggerlogger=Logger.getLogger(MyServer4.class.getName());
- publicstaticvoidmain(String[]args){
- Selectorselector=null;
- ServerSocketChannelserverSocketChannel=null;
- try{
- //Selectorforincomingtimerequests
- selector=Selector.open();
- //Createanewserversocketandsettononblockingmode
- serverSocketChannel=ServerSocketChannel.open();
- serverSocketChannel.configureBlocking(false);
- //Bindtheserversockettothelocalhostandport
- serverSocketChannel.socket().setReuseAddress(true);
- serverSocketChannel.socket().bind(newInetSocketAddress(10000));
- //Registeracceptsontheserversocketwiththeselector.This
- //steptellstheselectorthatthesocketwantstobeputonthe
- //readylistwhenacceptoperationsoccur,soallowingmultiplexed
- //non-blockingI/Ototakeplace.
- serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
- //Here'swhereeverythinghappens.Theselectmethodwill
- //returnwhenanyoperationsregisteredabovehaveoccurred,the
- //threadhasbeeninterrupted,etc.
- while(selector.select()>0){
- //SomeoneisreadyforI/O,getthereadykeys
- Iterator<SelectionKey>it=selector.selectedKeys().iterator();
- //Walkthroughthereadykeyscollectionandprocessdaterequests.
- while(it.hasNext()){
- SelectionKeyreadyKey=it.next();
- it.remove();
- //Thekeyindexesintotheselectorsoyou
- //canretrievethesocketthat'sreadyforI/O
- doit((ServerSocketChannel)readyKey.channel());
- }
- }
- }catch(ClosedChannelExceptionex){
- logger.log(Level.SEVERE,null,ex);
- }catch(IOExceptionex){
- logger.log(Level.SEVERE,null,ex);
- }finally{
- try{
- selector.close();
- }catch(Exceptionex){}
- try{
- serverSocketChannel.close();
- }catch(Exceptionex){}
- }
- }
- privatestaticvoiddoit(finalServerSocketChannelserverSocketChannel)throwsIOException{
- SocketChannelsocketChannel=null;
- try{
- socketChannel=serverSocketChannel.accept();
- receiveFile(socketChannel,newFile("E:/test/server_receive.log"));
- sendFile(socketChannel,newFile("E:/test/server_send.log"));
- }finally{
- try{
- socketChannel.close();
- }catch(Exceptionex){}
- }
- }
- privatestaticvoidreceiveFile(SocketChannelsocketChannel,Filefile)throwsIOException{
- FileOutputStreamfos=null;
- FileChannelchannel=null;
- try{
- fos=newFileOutputStream(file);
- channel=fos.getChannel();
- ByteBufferbuffer=ByteBuffer.allocateDirect(1024);
- intsize=0;
- while((size=socketChannel.read(buffer))!=-1){
- buffer.flip();
- if(size>0){
- buffer.limit(size);
- channel.write(buffer);
- buffer.clear();
- }
- }
- }finally{
- try{
- channel.close();
- }catch(Exceptionex){}
- try{
- fos.close();
- }catch(Exceptionex){}
- }
- }
- privatestaticvoidsendFile(SocketChannelsocketChannel,Filefile)throwsIOException{
- FileInputStreamfis=null;
- FileChannelchannel=null;
- try{
- fis=newFileInputStream(file);
- channel=fis.getChannel();
- ByteBufferbuffer=ByteBuffer.allocateDirect(1024);
- intsize=0;
- while((size=channel.read(buffer))!=-1){
- buffer.rewind();
- buffer.limit(size);
- socketChannel.write(buffer);
- buffer.clear();
- }
- socketChannel.socket().shutdownOutput();
- }finally{
- try{
- channel.close();
- }catch(Exceptionex){}
- try{
- fis.close();
- }catch(Exceptionex){}
- }
- }
- }
下面是Client程序代码,也主要关注sendFile和receiveFile方法
- packagecom.googlecode.garbagecan.test.socket.nio;
- importjava.io.File;
- importjava.io.FileInputStream;
- importjava.io.FileOutputStream;
- importjava.io.IOException;
- importjava.net.InetSocketAddress;
- importjava.net.SocketAddress;
- importjava.nio.ByteBuffer;
- importjava.nio.channels.FileChannel;
- importjava.nio.channels.SocketChannel;
- importjava.util.logging.Level;
- importjava.util.logging.Logger;
- publicclassMyClient4{
- privatefinalstaticLoggerlogger=Logger.getLogger(MyClient4.class.getName());
- publicstaticvoidmain(String[]args)throwsException{
- newThread(newMyRunnable()).start();
- }
- privatestaticfinalclassMyRunnableimplementsRunnable{
- publicvoidrun(){
- SocketChannelsocketChannel=null;
- try{
- socketChannel=SocketChannel.open();
- SocketAddresssocketAddress=newInetSocketAddress("localhost",10000);
- socketChannel.connect(socketAddress);
- sendFile(socketChannel,newFile("E:/test/client_send.log"));
- receiveFile(socketChannel,newFile("E:/test/client_receive.log"));
- }catch(Exceptionex){
- logger.log(Level.SEVERE,null,ex);
- }finally{
- try{
- socketChannel.close();
- }catch(Exceptionex){}
- }
- }
- privatevoidsendFile(SocketChannelsocketChannel,Filefile)throwsIOException{
- FileInputStreamfis=null;
- FileChannelchannel=null;
- try{
- fis=newFileInputStream(file);
- channel=fis.getChannel();
- ByteBufferbuffer=ByteBuffer.allocateDirect(1024);
- intsize=0;
- while((size=channel.read(buffer))!=-1){
- buffer.rewind();
- buffer.limit(size);
- socketChannel.write(buffer);
- buffer.clear();
- }
- socketChannel.socket().shutdownOutput();
- }finally{
- try{
- channel.close();
- }catch(Exceptionex){}
- try{
- fis.close();
- }catch(Exceptionex){}
- }
- }
- privatevoidreceiveFile(SocketChannelsocketChannel,Filefile)throwsIOException{
- FileOutputStreamfos=null;
- FileChannelchannel=null;
- try{
- fos=newFileOutputStream(file);
- channel=fos.getChannel();
- ByteBufferbuffer=ByteBuffer.allocateDirect(1024);
- intsize=0;
- while((size=socketChannel.read(buffer))!=-1){
- buffer.flip();
- if(size>0){
- buffer.limit(size);
- channel.write(buffer);
- buffer.clear();
- }
- }
- }finally{
- try{
- channel.close();
- }catch(Exceptionex){}
- try{
- fos.close();
- }catch(Exceptionex){}
- }
- }
- }
- }
首先运行MyServer4类启动监听,然后运行MyClient4类来向服务器发送文件以及接受服务器响应文件。运行完后,分别检查服务器和客户端接收到的文件。