网络编程典例解析
需求:多个客户端上传某一盘下所有MP3本地文件到同一个服务,服务器接收文件并保存到本地。
需求分析:
1.遍历某一盘符下的所有文件需要使用递归算法
2.服务端向客户端上传信息需要使用tcp通信
实现代码如下
- 服务端
package server_client;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//建立服务端基站,服务器需要持续运行
ServerSocket sst=new ServerSocket(2256);
System.out.println("基站已建立,等待访问");
while(true){
//每当有客户端请求链接时创建链接端口
Socket socket = sst.accept();
System.out.println("======================\n客户端访问,访问者信息:\n\tIP:"+socket.getInetAddress());
//当有多个客户端同一时间访问时,创建多个线程对象
new Thread(){
@Override
public void run(){
try {
//获取网络输入/输出流
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
//filePath存放从客户端接收到的文件名,用于提供保存到服务器本地时的文件路径
String filePath="";
//创建缓存数组通常为1024*8
byte [] bs=new byte[8192];
//接收服务端传输来的文件名
int len;
len=is.read(bs);
filePath=new String(bs, 0, len);
//向服务端反馈信息。主要是为了避免传输速度过快,文件内容与文件名无法区分。
//只有客户端接受到服务端反馈的信息,客户端才会继续传输文件内容,否则客户端阻塞。
os.write(1);
//创建文件输出流,用于将数据从服务器程序写入本地文件
FileOutputStream fos=new FileOutputStream(filePath);
System.out.println("传输中,请勿执行其它操作。");
while((len=is.read(bs))!=-1){
//将从客户端接收到的数据保存到本地
fos.write(bs, 0, len);
}
System.out.println("文件传输完毕\n======================");
//关闭文件输出流(节省资源)
fos.close();
//客户端保存完资料后
os.write("接受完毕".getBytes());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
//关闭本次线程链接
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
}
}
- 客户端
package server_client;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
File file=new File("G:\\");
serch(file);
}
public static void serch(File file){
//判断路径是否存在如果路径不存在方法结束
if(!file.exists()){
System.out.println("==路径名错误==");
return;
}
//如果文件名存在,则获取该路径下的子文件路径数组
File[] files = file.listFiles();
//如果数组不为空
if(files!=null){
//对子路径数组进行遍历
for(File sonfile : files){
//如果子路径为目录
if(sonfile .isDirectory()){
//以该子路径为根路径重新调用serch方法
serch(sonfile);
//如果子路径为文件
}else if(sonfile.isFile()){
//如果文件是以.mp3结尾的文件
if(sonfile.getName().endsWith(".mp3")){
try {
//调用send()方法。
send(sonfile);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
public static void send(File file) throws Exception{
//建立客户端基站并向对应信息的服务器发起链接请求,如果未获取到链接则报错
Socket socket=new Socket("192.168.2.108", 2256);
//获取网络输入输出流
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
//创建缓存数组
byte [] bs=new byte[8192];
int len;
//向服务段发送文件名
os.write(file.getName().getBytes());
//接受服务端的反馈信息
is.read();
//获取文件输入流,用于读取对应的本地文件进入客户端程序
FileInputStream fis =new FileInputStream(file);
//向服务端传输信息
while((len=fis.read(bs))!=-1){
os.write(bs,0,len);
System.out.println("\t数据传输中,请等待......");
}
System.out.println("==数据传输完毕==");
//关闭文件输入流,节省资源
fis.close();
//禁用socket套接字中输出流(while()os.write() 这个情况一定要禁用一下,否则对方输入流is 收不到-1)
socket.shutdownOutput();
len= is.read(bs);
System.out.println(new String(bs, 0, len));
socket.close();
}