描述:
(1)jdk自带线程池见 JDK自带线程池配置
(2)此上传文件服务器中上传文件的后缀名通过第一段缓冲字符流传递,此缓冲字符流大小为1024,在文件接收端以1024接收、处理。
1、服务器代码如下(使用jdk自带线程池):
1 /** 2 * 服务器处理多线程问题 3 * 4 * 1.因为服务器是要很多人访问的,因此里面一定要用多线程来处理,不然只能一个人一个人的访问,那还叫Y啥服务器 5 * 6 * 2,拿上面这个文件上传的例子来说,它将每个连接它的用户封装到线程里面去,把用户要执行的操作定义到 run 方法里面 7 * 一个用户拿一个线程,拿到线程的就自己去执行,如果有其它用户来的时候,再给新来的用户分配一个新的线程 这样就完成了服务器处理多线程的问题 3. 8 * 在服务器与客户端互传数据时,我们要特别注意的是,防止两个程序造成 死等的状态,一般原因有以下: 9 * 10 * 1. 客户端向数据端发送数据时,当发送的是字符时,第次以一行来发送,而服务端在读取的时候,也是以 一行来读取,readLine() 11 * 而发送的时候往往只是发送换行以行的内容,而不能发换行也发送过去, 那么服务端在读取的时候就不读取不到换行 ,那么 readLine() 就不会停止 2. 12 * 客户端发送数据时,如果处理的是用 字符流 或是缓冲流的话,一定要记得刷新流,不然的话,数据就会发不出来 3 在用IO 读取文件里面的数据然后发送到服务端 13 * 时,当家读取文件 while(in.read()) 读取文件结束时,而在 服务端的接收程序 14 * while(sin.read())不会接到一个发送完毕的提示,所以会一直等待下去,所以我们在处理这 15 * 个问题的时候,还要将其发送一个文件读取结束的标志,告诉接收端文件已经读取完结,不要再等待了 而socket 里面给我们封装了 shutdownInput 16 * shutdownOutput 两个操作,此可以关闭 流,两样也可以起到告诉 接收方文件传送完毕的效果 17 * 18 * 19 * 20 * */ 21 public class Server { 22 23 private static Logger logger = LoggerFactory.getLogger(Server.class); 24 private static final Integer PORT = 2222; 25 26 27 public static void main(String args[]) throws Exception { 28 29 ServerSocket server = new ServerSocket(PORT); 30 31 logger.info("服务器启动:::端口号为:{}",PORT); 32 ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 300, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(3), 33 new ThreadPoolExecutor.CallerRunsPolicy()); 34 35 while (true) { 36 37 Socket client = server.accept(); 38 executor.execute(new UploadThread(client)); 39 // new Thread(new UploadThread(client)).start(); 40 } 41 42 } 43 }
2、上传文件代码如下:
package cn.iautos.manager.test.load; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Timer; import java.util.TimerTask; public class Upload { public static void main(String args[]) throws Exception { Timer timer = new Timer(); timer.schedule(new TimerTask() { public void run() { try { System.out.println("--------开始上传文件-------"); loadMethod(); } catch (Exception e) { e.printStackTrace(); } } }, 0, 500); } public static void loadMethod() throws Exception{ String name = "E:\\qqq.jpg"; Socket client = new Socket("127.0.0.1", 2222); File file = new File(name); String imgSuffix = ImgUtils.getImgSuffix(name); BufferedInputStream fin = new BufferedInputStream(new FileInputStream( file)); // 文件读取流 PrintStream sout = new PrintStream(client.getOutputStream(), true); // 得到socket流 /** * 添加后缀名 */ byte[] b = new byte[1024]; byte[] bb = (imgSuffix+"\n").getBytes(); for(int j = 0;j<bb.length;j++){ b[j] = bb[j]; } sout.write(b,0,b.length); int len = 0; while ((len = fin.read(b)) != -1) { sout.write(b, 0, len); System.out.println(len + "...发送中"); } client.shutdownOutput(); BufferedInputStream sin = new BufferedInputStream(client .getInputStream()); len = sin.read(b); System.out.println(len); System.out.println(new String(b, 0, len)); sin.close(); sout.close(); fin.close(); } }
3、接收文件代码如下:
package cn.iautos.manager.test.load; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; import java.net.Socket; public class UploadThread implements Runnable // 将上传封装到线程里 { private Socket client; public UploadThread(Socket s) { this.client = s; } public void run() { // String ip = client.getInetAddress().getHostAddress(); // 得到 IP地址 try { BufferedInputStream sin = new BufferedInputStream(client.getInputStream()); // Socket 读取流 byte b[] = new byte[1024]; int l = sin.read(b); String line = new String(b, 0, l).split("\n")[0]; System.out.println("--------文件后缀为------"+line); File file = new File("E:\\loadServer\\" + ImgUtils.getImgName() + line); BufferedOutputStream fout = new BufferedOutputStream( new FileOutputStream(file)); // 文件输出流 int len = 0; // 开始从网络中读取数据 while (true) { len = sin.read(b); if(len != -1){ fout.write(b, 0, len); }else{ break; } // System.out.println("--------------"+new String(buf,0,len)); } PrintStream sout = new PrintStream(client.getOutputStream()); sout.write("发送成功".getBytes()); // sout.flush(); //虽然是字节流,但其用的是BufferedOutputStream fout.close(); sin.close(); sout.close(); } catch (Exception ex) { System.out.println(); ex.printStackTrace(); } } }