黑马程序员技术交流社区

标题: 加线程的TCP程序 [打印本页]

作者: 淡忘初学者    时间: 2015-8-24 12:12
标题: 加线程的TCP程序
       当我们编写网络编程基础程序时,当遇到服务端若为单线程时往往会有局限性,当A客户端连接上后,被服务端获取到,服务端执行具体流程,此时若遇到B客户端来连接,B客户端只有等待。因为服务端还没有处理完A客户端的请求,还要循环回到执行下次的accept才可接收,所以暂时获取不到B客户端对象。那么,为了可以让客户端同时并发访问服务端,那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求:
      那么我们应该如何定义线程呢?
     只要明确了每一个客户端执行的代码即可,将该代码存入到run方法中(注意:客户端执行的代码是在服务端中的哦!):
     接下来使用客户端向服务端上传png格式图片代码举例:
  1. import java.io.*;
  2. import java.net.*;

  3. class Text_Client {//定义客户端
  4. public static void main(String[] args)throws Exception {//为防止出现传输异常,先抛出异常
  5.                 if (args.length!=1){//判断是否上传了文件
  6.                         System.out.println("请选择一个png格式的图片:");
  7.                         return;
  8.                 }
  9.                 File file=new File(args[0]);
  10.                 if (!(file.exists()&&file.isFile()){//判断文件是否存在或者是否为文件
  11.                         System.out.println("该文件有问题,要么不存在,要么就不是文件");
  12.                         return;
  13.                 }
  14.                 if(!(file.getName().endsWith(".png"))){//是否为png格式图片
  15.                         System.out.println("图片格式错误,请重新选择");
  16.                         return;
  17.                 }
  18.                 if (file.length()>1024*1024*5){//防止传输文件大小过大
  19.                         System.out.println("文件过大");
  20.                         return;
  21.                 }
  22.                 Socket s=new Socket("192.168.1.105",10007);//创建TCP服务,并指定ip和端口
  23.                 FileInputStream fis=new FileInputStream(file);
  24.                 OutputStream out=s.getOutputStream();//获取输出流
  25.                 int leng=0;
  26.                 byte[] buf =new byte[1024];
  27.                 while((leng=fis.read(buf))!=-1){
  28.                         out.write(buf,0,leng);
  29.                 }
  30.                 s.shutdownOutput();//关闭客户端输出流,相当于给流中添加了一个结束标记-1
  31.                 InputStream In=s.getInputStream();//获取输入流,接收服务端传输过来的数据
  32.                 byte[] bufIn=new byte[1024];
  33.                 int num=In.read(bufIn);
  34.                 System.out.println(new String(bufIn,0,num));//打印数据
  35.                 fis.close();
  36.                 s.close();//关闭资源
  37.         }
  38. }
  39. class PicThread implements Runnable{//定义线程实现Runnable接口
  40.         private Socket s;
  41.         PicThread(Socket s){
  42.                 this.s=s;
  43.         }
  44.         public void run(){//覆盖run方法
  45.                 int count=0;
  46.                 String ip =s.getInetAddress().getHostAddress();//获取ip
  47.                 try{
  48.                         System.out.println(ip+"...connected");
  49.                         InputStream In=s.getInputStream();//获取输入流
  50.                         File file=new File(ip+"("+(++count)+")"+".png");
  51.                         while(file.exists()){//保存图片
  52.                                 file=new File(ip+"("+(++count)+")"+".png");
  53.                         }
  54.                         FileOutputStream fos=new FileOutputStream(file);
  55.                         byte[] buf=new byte[1024];
  56.                         int leng=0;
  57.                         while((leng=In.read(buf))!=-1){
  58.                                 fos.write(buf,0,leng);
  59.                         }
  60.                         OutputStream out=s.getOutputStream();<span style="line-height: 30.7999992370605px;">//获取输出流反馈信息</span>
  61.                         out.write("上传成功".getBytes());
  62.                         fos.close();
  63.                         s.close();//关闭资源
  64.                 }
  65.                 catch (Exception e){
  66.                         throw new RuntimeException(ip+"上传失败");
  67.                 }
  68.         }
  69. }
  70. class Text_Server {//定义服务端创立线程
  71.         public static void main(String[] args)throws Exception {
  72.                 ServerSocket ss=new ServerSocket(10007);
  73.                 while(true){
  74.                 Socket s=ss.accept();
  75.                 new Thread(new PicThread(s)).start();
  76.                 }
  77.                 //ss.close();      不需要关闭ss资源,因为要持续接收文件
  78.         }
  79. }
复制代码
         以上程序可以实现多个客户端对服务端数据的上传,服务端把每次上传的文件以ip+数字循环命名,防止文件名重复。



作者: boboyuwu    时间: 2015-8-24 12:26
到现在还搞不明白main中的String[]  和args分别是什么参数  用来干嘛的
作者: 淡忘初学者    时间: 2015-8-24 12:29
boboyuwu 发表于 2015-8-24 12:26
到现在还搞不明白main中的String[]  和args分别是什么参数  用来干嘛的

String[] args 是代表字符串型的数组,我们的代码是通过它输入到程序中运行的
作者: 淡忘初学者    时间: 2015-8-24 12:31
boboyuwu 发表于 2015-8-24 12:26
到现在还搞不明白main中的String[]  和args分别是什么参数  用来干嘛的

这是我的理解,但也不一定正确
作者: 黄蒙    时间: 2015-8-24 13:08
刚学完就有这么给力的代码。。我还纳闷呢怎么多线程处理多个客户端
作者: boboyuwu    时间: 2015-8-24 15:37
实在搞不懂  if (args.length!=1){//判断是否上传了文件   这局由来   怎么凭这个就能判断文件是否上传呢  还有既然主函数是void 还return干嘛
作者: 淡忘初学者    时间: 2015-8-24 16:47
boboyuwu 发表于 2015-8-24 15:37
实在搞不懂  if (args.length!=1){//判断是否上传了文件   这局由来   怎么凭这个就能判断文件是否上传呢  ...

因为我这个程序设计的文件上传是通过控制台指定文件,通过args数组存入的,每一个args数组每一个元素可以存入一个文件
C:\Users\luo\Desktop、1.png

作者: 淡忘初学者    时间: 2015-8-24 16:48
boboyuwu 发表于 2015-8-24 15:37
实在搞不懂  if (args.length!=1){//判断是否上传了文件   这局由来   怎么凭这个就能判断文件是否上传呢  ...

C:\Users\luo\Desktop\1.png
作者: 淡忘初学者    时间: 2015-8-25 20:48
黄蒙 发表于 2015-8-24 13:08
刚学完就有这么给力的代码。。我还纳闷呢怎么多线程处理多个客户端

要多次运行客户端哦~~然后用一个服务端接收
作者: 朱艳    时间: 2015-8-29 20:50
现在TCP用的好像不多吧




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2