import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
public class NewSocketServer {
private static final int port = 9527;
private Selector selector;
private ByteBuffer clientBuffer = ByteBuffer.allocate(1024);
private CharsetDecoder decoder = Charset.forName("GB2312").newDecoder();
private CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();
//编码解码格式设置成GBK也行.UTF-8不行,中文乱码 (前提都是客户端没有设置任何编码解码格式)
public void setListener() throws Exception {
selector = Selector.open(); //打开选择器
ServerSocketChannel server = ServerSocketChannel.open(); //定义一个 ServerSocketChannel通道
server.socket().bind(new InetSocketAddress(port)); // ServerSocketChannel绑定端口
server.configureBlocking(false); //配置通道使用非阻塞模式
server.register(selector, SelectionKey.OP_ACCEPT); //该通道在selector上注册 接受连接的动作
while (true) {
selector.select(); //select() 会阻塞,直到在该selector上注册的channel有对应的消息读入
Iterator iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = (SelectionKey)iter.next();
iter.remove(); // 删除此消息
process(key); // 当前线程内处理。(为了高效,一般会在另一个线程中处理此消息)
}
}
}
private void process(SelectionKey key) throws IOException {
if (key.isAcceptable()) { // 接收请求
ServerSocketChannel server = (ServerSocketChannel)key.channel();
SocketChannel channel =
server.accept(); //类似于io的socket,ServerSocketChannel的accept函数返回 SocketChannel
channel.configureBlocking(false); //设置非阻塞模式
SelectionKey sKey = channel.register(selector, SelectionKey.OP_READ);
sKey.attach("read_command"); //这儿接收到连接请求之后可以为每个连接设置一个ID
} else if (key.isReadable()) { // 读信息
SocketChannel channel = (SocketChannel)key.channel();
String name = (String)key.attachment();
if (name.equals("read_command")) {
int count = channel.read(clientBuffer);
if (count > 0) {
clientBuffer.flip();
CharBuffer charBuffer = decoder.decode(clientBuffer);
String command =charBuffer.toString(); //command形如:get abc.png 或者 put aaa.png
System.out.println("command====" +command); //得到客户端传来的命令
String[] temp = command.split(" ");
command = temp[0]; //命令 是put还是get
String filename = temp[1]; //文件名
SelectionKey sKey = channel.register(selector, SelectionKey.OP_WRITE);
if (command.equals("put"))
sKey.attach("UploadReady#" + filename); //要保护该通道的文件名
else if (command.equals("get")) {
if (!new File("C:\\temp\\", filename).exists()) { //假设文件都是在C盘根目录
System.out.println("没有这个文件,无法提供下载!");
sKey.attach("notexists");
} else
sKey.attach("DownloadReady#" + filename); //要保护该通道的文件名
}
} else {
channel.close();
}
} else if (name.startsWith("read_file")) { //这儿可以新开一个线程 文件操作也可以用NIO
DataOutputStream fileOut =
new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File("C:\\temp\\",
name.split("#")[1]))));
int passlen = channel.read(clientBuffer);
while (passlen >= 0) {
clientBuffer.flip();
fileOut.write(clientBuffer.array(), 0, passlen);
passlen = channel.read(clientBuffer);
}
System.out.println("上传完毕!");
fileOut.close();
channel.close();
}
clientBuffer.clear();
} else if (key.isWritable()) { // 写事件
SocketChannel channel = (SocketChannel)key.channel();
String flag = (String)key.attachment();
if (flag.startsWith("downloading")) { //这儿可以新开一个线程 文件操作也可以用NIO
DataInputStream fis =
new DataInputStream(new BufferedInputStream(new FileInputStream(new File("C:\\", flag.split("#")[1]))));
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
channel.write(ByteBuffer.wrap(buf, 0, len));
}
fis.close();
System.out.println("文件传输完成");
channel.close();
} else if (flag.equals("notexists")) {
//channel.write(encoder.encode(CharBuffer.wrap(flag)));
channel.write(ByteBuffer.wrap(flag.getBytes())); //不用编码也行 客户端直接接收 中文也不是乱码
channel.close();
} else if (flag.startsWith("UploadReady")) {
channel.write(encoder.encode(CharBuffer.wrap("UploadReady"))); //这儿如果不重新注册该通道的读操作 selector选择到该通道的将继续永远是写操作,也就无法跳转到上面的接受上传的处理
SelectionKey sKey = channel.register(selector, SelectionKey.OP_READ); //register是覆盖的????!!!
sKey.attach("read_file#" + flag.split("#")[1]);
//key.attach("read_file#"+flag.split("#")[1]); //select不到读操作
} else if (flag.startsWith("DownloadReady")) {
channel.write(ByteBuffer.wrap("准备下载".getBytes()));
//channel.write(encoder.encode(CharBuffer.wrap("准备下载")));
key.attach("downloading#" + flag.split("#")[1]);
}
}
}
public static void main(String[] args) {
try {
System.out.println("等待来至" + port + "端口的客户端连接.....");
new NewSocketServer().setListener();
} catch (Exception e) {
e.printStackTrace();
}
}
}
///client
package test;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class ClientMain {
private int ServerPort = 9527;
private String ServerAddress = "localhost";
private String GetOrPut = "get";
private String local_filename = "";
private String remote_filename = "";
private byte[] buf;
private int len;
class SocketThread extends Thread {
@Override
public void run() {
try {
File file = new File("C:\\temp\\", local_filename); //假设文件放在C盘
if (!file.exists() && GetOrPut.equals("put")) {
System.out.println("本地没有这个文件,无法上传!");
return;
}
//InetAddress loalhost = InetAddress.getLocalHost();
Socket socket =
new Socket(ServerAddress, ServerPort); //服务器IP地址 端口号 本机IP 本机端口号
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
//dos.writeUTF(GetOrPut+" "+remote_filename);//服务器端如果是io的socket,writeUTF和writeUTF对接
dos.write((GetOrPut + " " + remote_filename).getBytes());
dos.flush();
//String tempString = dis.writeUTF();
buf = new byte[1024];
len = dis.read(buf);
String tempString = new String(buf, 0, len); //服务器反馈的信息
//System.out.println(tempString);
if (tempString.equals("notexists")) {
System.out.println("服务器没有这个文件,无法下载!");
dos.close();
dis.close();
socket.close();
return;
}
if (tempString.startsWith("准备下载")) {
DataOutputStream fileOut =
new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
while ((len = dis.read(buf)) != -1) {
fileOut.write(buf, 0, len);
}
System.out.println("下载完毕!");
fileOut.close();
dos.close();
dis.close();
socket.close();
} else if (tempString.equals("UploadReady")) {
System.out.println("正在上传文件.......");
DataInputStream fis = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
while ((len = fis.read(buf)) != -1) {
dos.write(buf, 0, len);
}
dos.flush();
System.out.println("上传完毕!");
fis.close();
dis.close();
dos.close();
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public boolean checkCommand(String command) {
if (!command.startsWith("put") && !command.startsWith("get")) {
System.out.println("输入命令错误");
return false;
}
int index = -1;
String temp = "";
String[] tempStrings = null;
if ((index = command.indexOf("-h")) > 0) {
temp = command.substring(index + 3);
temp = temp.substring(0, temp.indexOf(' '));
ServerAddress = temp;
}
if ((index = command.indexOf("-p")) > 0) {
temp = command.substring(index + 3);
temp = temp.substring(0, temp.indexOf(' '));
ServerPort = Integer.valueOf(temp);
}
tempStrings = command.split(" ");
if (command.startsWith("put")) {
GetOrPut = "put";
local_filename = tempStrings[tempStrings.length - 2];
remote_filename = tempStrings[tempStrings.length - 1];
} else if (command.startsWith("get")) {
GetOrPut = "get";
local_filename = tempStrings[tempStrings.length - 1];
remote_filename = tempStrings[tempStrings.length - 2];
}
return true;
}
public static void main(String[] args) {
ClientMain thisC = new ClientMain();
Scanner sc = new Scanner(System.in);
String commandString = "";
do {
System.out.println("请输入命令:");
commandString = sc.nextLine();
} while (!thisC.checkCommand(commandString));
ClientMain.SocketThread a = thisC.new SocketThread();
a.start();
}
}