接《java网络编程实例2.1——用阻塞+线程池实现的文件传输客户端》
【服务器代码】
package s_transfer_file;
import java.io.*;
public class App
{
public static void main(String[] args) throws IOException
{new ServerTransferFile().work();}
}
package s_transfer_file;
import java.io.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
public class ServerTransferFile //文件传输服务器
{
ServerSocketChannel serverSocketChannel;
Selector selector;
ServerTransferFile() throws IOException
{
/*********创建并绑定ServerSocketChannel*********/
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(5299));
/*********创建并绑定ServerSocketChannel*********/
/*********注册有连接请求事件*********/
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
/*********注册有连接请求事件*********/
}
public void work() throws IOException
{
/*********工作循环*********/
while(true)
{
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
/*********对所有发生事件的契约进行处理*********/
Iterator<SelectionKey> selectedKeysIter = selectedKeys.iterator();
while(selectedKeysIter.hasNext()) //对每一个契约
{
SelectionKey aSelectedKey = selectedKeysIter.next();
selectedKeysIter.remove();
if(aSelectedKey.isAcceptable()) //如果有连接请求
{
/*********接收请求,注册客户端可读可写事件*********/
SocketChannel clientSocketChannel = serverSocketChannel.accept();
clientSocketChannel.configureBlocking(false);
TransferHelper helper = new TransferHelper();
helper.clientName = ((InetSocketAddress)clientSocketChannel.getRemoteAddress()).getHostName();
helper.stage = 0;
helper.transfered = -1;
helper.buffer.limit(4);
clientSocketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE, helper);
/*********接收请求,注册客户端可读可写事件*********/
}
if(aSelectedKey.isReadable()) //如果客户端可读
{
/*********接收数据*********/
SocketChannel clientSocketChannel = (SocketChannel)aSelectedKey.channel();
TransferHelper helper = (TransferHelper)aSelectedKey.attachment();
try
{clientSocketChannel.read(helper.buffer);}
catch(IOException e) //读的时候客户端强制终止连接
{
if(helper.readFileChannel != null)
helper.readFileChannel.close();
else if(helper.writeFileChannel != null) //如果已经在服务器建立了文件
{
helper.writeFileChannel.close();
new File(helper.fileName).delete();
}
if(helper.clientName != null && helper.fileName != null) //如果已经解析出文件名
System.out.println(helper.clientName+"强制中断了文件"+helper.fileName+"的传输");
clientSocketChannel.close();
continue;
}
/*********接收数据*********/
if(helper.stage == 0) //如果在请求阶段
{
if(helper.transfered == -1) //如果还没有读到字节数
{
if(helper.buffer.position() == 4) //如果可以读字节数了
{
/*********读字节数*********/
helper.buffer.rewind();
helper.len = helper.buffer.getInt();
helper.buffer.clear();
helper.transfered = 0;
/*********读字节数*********/
}
}
else //如果读到字节数了
{
if(helper.buffer.position() == helper.len) //如果可以读请求了
{
/*********读请求*********/
helper.buffer.flip();
String request = Charset.forName("utf-8").decode(helper.buffer).toString();
helper.buffer.clear();
helper.stage = 1;
helper.transfered = -1;
/*********读请求*********/
/*********解析请求*********/
if(request.startsWith("GET "))
helper.download = true;
else
helper.download = false;
helper.fileName = request.substring(4);
/*********解析请求*********/
}
}
}
else if(helper.stage == 2 && !helper.download) //如果在文件上传阶段
{
if(helper.transfered == -1) //如果还没有读到字节数
{
if(helper.buffer.position() == 4) //如果可以读字节数了
{
/*********读字节数*********/
helper.buffer.flip();
helper.len = helper.buffer.getInt();
helper.buffer.clear();
helper.transfered = 0;
/*********读字节数*********/
}
}
else //如果已经读到字节数了
{
/*********接收和转存文件*********/
helper.buffer.flip();
helper.transfered += helper.writeFileChannel.write(helper.buffer);
helper.buffer.clear();
if(helper.transfered == helper.len) //如果文件传输完成
{
helper.writeFileChannel.close();
System.out.println("来自"+helper.clientName+"的"+helper.fileName+"接收完成");
clientSocketChannel.close(); //也就不再监听此客户是否可读写
continue;
}
/*********接收和转存文件*********/
}
}
}
if(aSelectedKey.isWritable()) //如果是客户端可写
{
SocketChannel clientSocketChannel = (SocketChannel)aSelectedKey.channel();
TransferHelper helper = (TransferHelper)aSelectedKey.attachment();
if(helper.stage == 1) //如果在响应阶段
{
if(helper.transfered == -1) //如果还没准备好响应信息
{
/*********准备响应信息*********/
String response; //响应信息
if(helper.download) //如果是要下载
{
try
{
helper.readFileChannel = new FileInputStream(helper.fileName).getChannel();
response = "OK";
}
catch(FileNotFoundException e)
{response = "服务器上不存在文件"+helper.fileName;}
}
else //如果是要上传
{
try
{
helper.writeFileChannel = (new FileOutputStream(helper.fileName)).getChannel();
response = "OK";
}
catch(FileNotFoundException e)
{response = "无法在服务器上建立文件"+helper.fileName;}
}
byte[] responseBytes = response.getBytes(Charset.forName("utf-8"));
helper.buffer.putInt(responseBytes.length);
helper.buffer.put(responseBytes);
helper.buffer.flip();
/*********准备响应信息*********/
helper.transfered = 0;
}
else //如果准备好响应信息了
{
try
{clientSocketChannel.write(helper.buffer);} //发送响应信息
catch(IOException e) //如果客户端强制断开了连接
{
System.out.println(helper.clientName+"强制中断了文件"+helper.fileName+"的传输");
if(helper.download)
helper.readFileChannel.close();
else
{
helper.writeFileChannel.close();
new File(helper.fileName).delete();
}
clientSocketChannel.close();
continue;
}
if(helper.buffer.remaining() == 0) //如果响应信息发完了
{
/*********准备进入下一阶段*********/
helper.buffer.position(4);
if(!Charset.forName("utf-8").decode(helper.buffer).toString().equals("OK")) //如果响应信息不是OK
{
clientSocketChannel.close(); //那么通信就结束了
continue;
}
helper.buffer.clear();
if(!helper.download) //如果是要上传
helper.buffer.limit(4);
helper.stage = 2;
helper.transfered = -1;
/*********准备进入下一阶段*********/
}
}
}
else if(helper.stage == 2 && helper.download) //如果文件在下载阶段
{
if(helper.transfered == -1) //如果还没准备好数据
{
/*********准备数据*********/
helper.buffer.putInt((int)new File(helper.fileName).length());
helper.readFileChannel.read(helper.buffer);
helper.buffer.flip();
/*********准备数据*********/
helper.transfered = 0;
}
else //如果已经准备好数据了
{
try
{helper.transfered += clientSocketChannel.write(helper.buffer);} //发送数据
catch(IOException e)
{
System.out.println(helper.clientName+"强制中断了文件"+helper.fileName+"的传输");
helper.readFileChannel.close();
clientSocketChannel.close();
continue;
}
/*********填充缓冲区*********/
helper.buffer.compact();
helper.readFileChannel.read(helper.buffer);
helper.buffer.flip();
/*********填充缓冲区*********/
if(helper.buffer.limit() == 0) //如果发送完了
{
helper.readFileChannel.close();
System.out.println(helper.fileName+"已向"+helper.clientName+"发送完成");
clientSocketChannel.close();
continue;
}
}
}
}
}
/*********对所有发生事件的契约进行处理*********/
}
/*********工作循环*********/
}
}
package s_transfer_file;
import java.nio.*;
import java.nio.channels.*;
public class TransferHelper //文件传输助手
{
public String clientName; //客户端主机名
public boolean download; //客户端是要下载
public String fileName; //文件名
public int stage; //传输阶段:0=请求,1=响应,2=文件
public int len; //本阶段要传送的字节数
public int transfered; //已传送字节数。读socket:为-1表示还没接收要传的字节数。写socket:为-1表示还没准备好要传的字节数
public ByteBuffer buffer; //缓冲区
public FileChannel readFileChannel; //读文件通道
public FileChannel writeFileChannel; //写文件通道
public TransferHelper()
{
clientName = null;
fileName = null;
buffer = ByteBuffer.allocate(1024);
readFileChannel = null;
writeFileChannel = null;
}
}
未完待续