java网络编程实例2.1——用阻塞+线程池实现的文件传输客户端


【任务】

写一个文件传输服务器和客户端。客户端用“GET 文件名”和“PUT 文件名”请求下载或上传文件。

这里要自定义文件传输协议。每传输一个文件都新建立一个连接,首先是客户端发送请求长度和请求内容,接着服务器根据自身情况向发送响应长度和响应内容,然后文件的发送方发送文件长度和文件内容,最后关闭连接。

为了能够练习尽量多的知识点,客户端用的是阻塞通信+线程池来实现的,服务端用的是非阻塞通信实现的。

现在的代码已经能正常行使功能,只是健壮性不强,所以还不完美。


【客户端代码】

package c_transfer_file;

import java.io.*;

public class App
{
public static void main(String[] args) throws IOException, InterruptedException
{new ClientTransferFile("localhost").work();}
}
package c_transfer_file;import java.io.*;import java.util.concurrent.*;public class ClientTransferFile//文件传输客户端{String serverName;//服务器名BufferedReader keyboardIn;//键盘输入流ExecutorService threadPool;//线程池public ClientTransferFile(String serverName){this.serverName = serverName;keyboardIn = new BufferedReader(new InputStreamReader(System.in));//获得键盘输入流threadPool = Executors.newCachedThreadPool();//创建线程池}public void work() throws IOException, InterruptedException{/*********工作循环*********/while(true){/*********从键盘获取并解析用户要求*********/String command = keyboardIn.readLine();String command_up = command.toUpperCase();if(command_up.equals("Q"))break;else if(command_up.startsWith("GET ")){String fileName = command.substring(4);threadPool.submit(new TaskGetFile(serverName,fileName));}else if(command_up.startsWith("PUT ")){String fileName = command.substring(4);threadPool.submit(new TaskPutFile(serverName,fileName));}elseSystem.out.println(command+"是未定义的命令");/*********从键盘获取并解析用户要求*********/}/*********工作循环*********/keyboardIn.close();/*********关闭线程池*********/threadPool.shutdownNow();if(!threadPool.awaitTermination(30,TimeUnit.SECONDS)){threadPool.shutdownNow();System.out.println("强制关闭了线程池");}/*********关闭线程池*********/}}
package c_transfer_file;import java.util.concurrent.*;import java.io.*;import java.nio.channels.*;import java.nio.charset.*;import java.net.*;public class TaskGetFile implements Callable<Object>//线程任务:下载文件{String serverName;//服务器名String fileName;//下载文件的名称public TaskGetFile(String serverName, String fileName){this.serverName = serverName;this.fileName = fileName;}public Object call() throws IOException//线程任务的流程{/*********建立连接*********/InetSocketAddress serverPort = new InetSocketAddress(serverName, 5299);//服务器端口地址SocketChannel socketChannel;try{socketChannel = SocketChannel.open(serverPort);}//建立连接catch(UnsupportedAddressTypeException e){System.out.println(serverName+"是不支持的地址类型");return null;}catch(UnresolvedAddressException e){System.out.println("无法解析地址"+serverName);return null;}catch(ConnectException e){System.out.println(serverName+"拒绝了连接请求");return null;}//这里不要把SocketChannel关掉,因为SocketChannel还不存在/*********建立连接*********//*********获得网络输入输出流*********/Socket socket = socketChannel.socket();DataInputStream socketIn = new DataInputStream(new BufferedInputStream(socket.getInputStream()));DataOutputStream socketOut = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));/*********获得网络输入输出流*********//*********发送请求*********/byte[] requestBytes = ("GET "+fileName).getBytes(Charset.forName("utf-8"));socketOut.writeInt(requestBytes.length);socketOut.write(requestBytes);socketOut.flush();/*********发送请求*********//*********接收响应信息*********/int responseLen = socketIn.readInt();//响应信息的长度byte[] responseBytes = new byte[responseLen];//用于接收响应信息的字节数组socketIn.read(responseBytes);String response = new String(responseBytes, Charset.forName("utf-8"));//响应信息if(!response.equals("OK"))//如果响应信息表示没法下载{System.out.println(response);socketChannel.close();return null;}/*********接收响应信息*********//*********创建写文件流*********/BufferedOutputStream writeFileStream;try{writeFileStream = new BufferedOutputStream(new FileOutputStream(fileName));}catch(FileNotFoundException e){System.out.println("无法创建文件"+fileName);socketChannel.close();return null;}/*********创建写文件流*********//*********下载和转存文件*********/int fileLen = socketIn.readInt();//文件长度for(int i = 0; i < fileLen; i++)writeFileStream.write(socketIn.read());writeFileStream.flush();writeFileStream.close();/*********下载和转存文件*********/System.out.println("文件"+fileName+"下载完成");socketChannel.close();//断开连接return null;}}
package c_transfer_file;import java.util.concurrent.*;import java.io.*;import java.nio.charset.*;import java.net.*;import java.nio.channels.*;public class TaskPutFile implements Callable<Object>//线程任务:上传文件{String serverName;//服务器名String fileName;//上传文件的名称public TaskPutFile(String serverName, String fileName){this.serverName = serverName;this.fileName = fileName;}public Object call() throws IOException//线程任务的流程{/*********创建读文件流*********/BufferedInputStream readFileStream;try{readFileStream = new BufferedInputStream(new FileInputStream(fileName));}catch(FileNotFoundException e){System.out.println("文件"+fileName+"不存在");return null;}/*********创建读文件流*********//*********建立连接*********/InetSocketAddress serverPort = new InetSocketAddress(serverName, 5299);//服务器端口地址SocketChannel socketChannel;try{socketChannel = SocketChannel.open(serverPort);}//建立连接catch(UnsupportedAddressTypeException e){System.out.println(serverName+"是不支持的地址类型");readFileStream.close();return null;}catch(UnresolvedAddressException e){System.out.println("无法解析地址"+serverName);readFileStream.close();return null;}catch(ConnectException e){System.out.println(serverName+"拒绝了连接请求");readFileStream.close();return null;}//这里不要把SocketChannel关掉,因为SocketChannel还不存在/*********建立连接*********//*********获得网络输入输出流*********/Socket socket = socketChannel.socket();DataInputStream socketIn = new DataInputStream(new BufferedInputStream(socket.getInputStream()));DataOutputStream socketOut = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));/*********获得网络输入输出流*********//*********发送请求*********/byte[] requestBytes = ("PUT "+fileName).getBytes(Charset.forName("utf-8"));socketOut.writeInt(requestBytes.length);socketOut.write(requestBytes);socketOut.flush();/*********发送请求*********//*********接收响应信息*********/int responseLen = socketIn.readInt();//响应信息的长度byte[] responseBytes = new byte[responseLen];//用于接收响应信息的字节数组socketIn.read(responseBytes);String response = new String(responseBytes, Charset.forName("utf-8"));//响应信息if(!response.equals("OK"))//如果响应信息表示没法上传{System.out.println(response);socketChannel.close();readFileStream.close();return null;}/*********接收响应信息*********//*********读取和上传文件*********/int fileLen = readFileStream.available();//文件长度socketOut.writeInt(fileLen);for(int i = 0; i < fileLen; i++)socketOut.write(readFileStream.read());socketOut.flush();readFileStream.close();/*********读取和上传文件*********/socketChannel.close();//断开连接System.out.println("文件"+fileName+"上传完成");return null;}}
未完待续

智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告